package com.battery.system.service.battery.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.response.AlipayTradePayResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.battery.common.core.domain.AjaxResult;
import com.battery.common.core.text.Convert;
import com.battery.common.enums.*;
import com.battery.common.utils.*;
import com.battery.common.utils.ali.AliPayEntity;
import com.battery.common.utils.ali.AliPayUtils;
import com.battery.common.utils.dev.RLineUtils;
import com.battery.common.utils.dev.WsDevUtils;
import com.battery.common.utils.http.HttpClientJSONUtil;
import com.battery.common.utils.reckon.ReckonEntity;
import com.battery.common.utils.reckon.ReckonUtils;
import com.battery.common.utils.security.Md5Utils;
import com.battery.common.utils.wx.PayscoreUtils;
import com.battery.system.domain.*;
import com.battery.system.domain.BO.UsedBO;
import com.battery.system.domain.VO.StatisticsVO;
import com.battery.system.domain.VO.UsedDetailVo;
import com.battery.system.domain.VO.UsedOrder;
import com.battery.system.domain.VO.UsedVO;
import com.battery.system.mapper.*;
import com.battery.system.service.ISysConfigService;
import com.battery.system.service.battery.IIncomeService;
import com.battery.system.service.battery.IUsedService;
import com.battery.system.service.impl.BaseServiceImpl;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.n3r.idworker.Sid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 租借订单Service业务层处理
 *
 * @author battery
 * @date 2021-01-22
 */
@Service
public class UsedServiceImpl extends BaseServiceImpl<Used> implements IUsedService {
    @Autowired
    private UsedMapper usedMapper;


    @Autowired
    private Sid sid;


    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private DeviceBasicsMapper deviceBasicsMapper;


    @Autowired
    private ProrelyMapper prorelyMapper;


    @Autowired
    private UsedBasicsMapper usedBasicsMapper;

    @Autowired
    private StoreMapper storeMapper;


    @Autowired
    private ProjectMapper projectMapper;


    @Autowired
    private SysConfigMapper configMapper;


    @Autowired
    private StoreInstallMapper storeInstallMapper;


    @Autowired
    private AppUserMapper appUserMapper;


    @Autowired
    private MemberMapper memberMapper;


    @Autowired
    private AuthUsedMapper authUsedMapper;


    @Autowired
    private OrderMapper orderMapper;


    @Autowired
    private PartnerMapper partnerMapper;


    @Autowired
    private IIncomeService incomeService;


    @Autowired
    private ISysConfigService configService;


    @Autowired
    private PointsDetailMapper pointsDetailMapper;


    @Autowired
    private RefundOrderMapper refundOrderMapper;


    @Autowired
    private PartnerInstallMapper partnerInstallMapper;


    @Autowired
    private MerchantMapper merchantMapper;


    @Autowired
    private EventMapper eventMapper;


    //  微信支付
    @Autowired(required = false)
    private WxPayService wxService;

    /**
     * 查询租借订单
     *
     * @param id 租借订单ID
     * @return 租借订单
     */
    @Override
    public Used selectUsedById(String id) {
        return usedMapper.selectUsedById(id);
    }

    /**
     * 查询租借订单列表
     *
     * @param used 租借订单
     * @return 租借订单
     */
    @Override
    public List<Used> selectUsedList(Used used) {
        return usedMapper.selectUsedList(used);
    }

    /**
     * 新增租借订单
     *
     * @param used 租借订单
     * @return 结果
     */
    @Override
    public int insertUsed(Used used) {
        used.setCreateTime(DateUtils.getNowDate());
        return usedMapper.insertUsed(used);
    }

    /**
     * 修改租借订单
     *
     * @param used 租借订单
     * @return 结果
     */
    @Override
    public int updateUsed(Used used) {
        return usedMapper.updateUsed(used);
    }

    /**
     * 删除租借订单对象
     *
     * @param ids 需要删除的数据ID
     * @return 结果
     */
    @Override
    public int deleteUsedByIds(String ids) {
        return usedMapper.deleteUsedByIds(Convert.toStrArray(ids));
    }

    /**
     * 删除租借订单信息
     *
     * @param id 租借订单ID
     * @return 结果
     */
    @Override
    public int deleteUsedById(String id) {
        return usedMapper.deleteUsedById(id);
    }


    @Override
    public List<UsedVO> selectUsedVOList(UsedBO usedBO) {
        return usedMapper.selectUsedVOList(usedBO);
    }

    /**
     * 根据用户ID查询正在进行中的订单（最新）
     *
     * @param appUserId
     * @return
     */
    @Override
    public List<Used> selectOnLoan(String appUserId) {
        Example example = new Example(Used.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("leaseState", LeaseStateEnum.SUCCESS.getCode());
        criteria.andEqualTo("isBack", YesOrNoEnum.NO.getCode());
        criteria.andEqualTo("appUserId", appUserId);
        example.orderBy("createTime").desc();
        return usedMapper.selectByExample(example);
    }

    /**
     * 查询用户押金租借未支付的租借记录
     *
     * @param appUserId
     * @param channel
     * @param borrowMode
     * @return
     */
    @Override
    public Used selectOneNoPay(String appUserId, Integer channel, Integer borrowMode) {
        Example example = new Example(Used.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("leaseState", LeaseStateEnum.SUCCESS.getCode()); // 租借成功
        criteria.andEqualTo("isBack", YesOrNoEnum.YES.getCode()); // 归还成功
        criteria.andEqualTo("appUserId", appUserId);
        criteria.andEqualTo("channel", channel);
        criteria.andEqualTo("borrowMode", borrowMode);
        criteria.andEqualTo("status", UsedStatusEnum.TO_BE_PAID.getCode()); // 待支付
        example.orderBy("createTime").desc();
        return usedMapper.selectOneByExample(example);
    }


    /**
     * 判断这个时刻的设备是否是活动设备，且是否满足活动要求
     *
     * @param device
     * @param date
     * @return
     */
    private int checkDevIsActivity(Device device, Date date) {
        int i = 0;
        if (device != null && device.getIsActivity() != null && device.getIsActivity() == YesOrNoEnum.YES.getCode().intValue()) {
            // 该设备是活动设备
            Event event = eventMapper.selectByPrimaryKey(device.getEventId());
            if (event != null && event.getState() == 1) {
                // 活动是开启的，那么开始判断是否在活动时间之内
                Date eventEndTime = event.getEndTime();
                if (eventEndTime.getTime() - date.getTime() > 0) {
                    // 在活动时间之内，可分润. 那么要开始查询该设备的营业额是否已满足要求
                    BigDecimal eventNeedMoney = event.getActivateCondition();
                    BigDecimal devUsedTurnover = usedMapper.selectSumByDevId(device.getId());
                    if (devUsedTurnover.subtract(eventNeedMoney).compareTo(BigDecimal.ZERO) > 0) {
                        // 该设备营业额满足要求
                        i = 1;
                    }
                }
            }
        }
        return i;
    }

    /**
     * WS设备 押金租借 方式二 （强制弹出租借 + 传统方式租借）
     *
     * @param noUsedDeposit 押金订单
     * @param appUser       用户信息
     * @param storeInstall  门店
     * @param device        设备信息
     * @return
     */
    @Transactional
    @Override
    public BatteryJSONResult wsDevTips2DepositBorrowBattery(Order noUsedDeposit, AppUser appUser, StoreInstall storeInstall, Device device) {

        String sn = device.getSn();
        Prorely prorely = prorelyMapper.selectBySn(sn);
        if (prorely == null) {
            return BatteryJSONResult.errorMsg("设备【" + sn + "】租借依据不存在");
        }

        // TODO 计算当前该笔订单是否需要M
        int isM = 0;
        PartnerInstall partnerInstall = partnerInstallMapper.selectByPrimaryKey(device.getPartnerId());
        if (appUser.getIsFree() == 0) {
            isM = Mutils.isM(partnerInstall.getBorrowCount(), partnerInstall.getmBl());
        }

        String usedId = sid.nextShort();
        Date date = DateUtils.getNowDate();

        Used used = new Used();
        used.setId(usedId);
        used.setChannel(appUser.getUserType());// 订单渠道 微信 1 支付宝 2
        used.setOrderNumber(GenerateSeqUtil.generateSeqNo()); // order_number
        used.setBorrowMode(BorrowModeEnum.DEPOSIT.type); // 押金租借
        used.setProjectId(device.getProjectId()); // 平台-项目ID
        used.setPartnerId(device.getPartnerId()); // 合作商
        used.setMerchantId(device.getMerchantId()); // 商户
        used.setStoreId(device.getStoreId());
        used.setAppUserId(appUser.getId());
        used.setCreateTime(date);
        used.setFalseOrderId(noUsedDeposit.getId()); // 押金租借专用

        String storeName = "";
        if (storeInstall == null) {
            // 门店信息为空，该设备未部署
            storeName = "";
        } else {
            Store store = storeMapper.selectByPrimaryKey(storeInstall.getStoreId());
            if (store != null) {
                storeName = store.getStoreName();
            }
        }
        used.setStoreName(storeName);
        Project project = projectMapper.selectByPrimaryKey(device.getProjectId());
        used.setMealContent(getDevMealContent(storeInstall, project.getDeposit()));
        used.setIsM(isM);
        used.setIsActivity(checkDevIsActivity(device, date)); // 校验该设备是否满足要求
        used.setIsFree(appUser.getIsFree()); // VIP订单
        usedMapper.insertSelective(used);

        // TODO 记录租借次数
        PartnerInstall partnerInstall1Update = new PartnerInstall();
        partnerInstall1Update.setPartnerId(partnerInstall.getPartnerId());
        partnerInstall1Update.setBorrowCount(partnerInstall.getBorrowCount() + 1);
        partnerInstallMapper.updateByPrimaryKeySelective(partnerInstall1Update);


        UsedBasics basics = new UsedBasics();
        boolean flag = false;
        basics.setUsedId(usedId);
        basics.setRentDate(date);
        basics.setRentDeviceId(device.getId());
        basics.setRentDeviceSn(sn);
        basics.setDevType(device.getDevType());

        String borrowId = WsDevUtils.getWsBorrowId();
        DeviceBasics devBasics = deviceBasicsMapper.selectByPrimaryKey(device.getId());
        Date detailStockTime = devBasics.getDetailStockTime();
        if (date.getTime() - detailStockTime.getTime() < 300 * 1000) {

            // TODO 查询之前借用的电池
            String oldBatterySn = "";
            UsedBasics oldbasics = usedBasicsMapper.selectLatelyUsedBySn(device.getSn());
            if (oldbasics != null) {
                oldBatterySn = oldbasics.getBatterySn();
            }
            JSONObject batteryObj = WsDevUtils.getBorrowBatteryInfo(devBasics.getDetailStock(), devBasics.getLockBatterys(), oldBatterySn, prorely.getBps(), WsDevUtils.getWsSlotNum(device.getDevType()));
            if (batteryObj != null) {
                Integer toBorrowSlot = batteryObj.getInteger("slot");
                basics.setRentSlotNo(toBorrowSlot);
                basics.setBatterySn(batteryObj.getString("batterySn"));
                basics.setLeaseId("popup" + "_" + sn + "_" + toBorrowSlot + "_" + borrowId); // TODO TODO 注意，以timestamp作为租借ID 要考虑
                flag = true;
            }
        }

        if (!flag) {
            // 非强弹租借，正常方式租借
            basics.setLeaseId("borrow" + "_" + sn + "_" + borrowId); // TODO TODO 注意，以timestamp作为租借ID 要考虑
        }
        // 保存
        usedBasicsMapper.insertUsedBasics(basics);

        BatteryJSONResult result = null;
        try {
            String service = prorely.getService();
            int port = prorely.getPort() + 100;

            String salt = Constants.ws_borrow_slat; // 加密盐
            JSONObject requestObj = new JSONObject();
            requestObj.put("sn", device.getSn());
            String before = "";
            String url = "";
            if (flag) {
                // 强弹租借
                requestObj.put("slot", basics.getRentSlotNo());
                requestObj.put("charge", YesOrNoEnum.YES.getCode());
                before = sn + basics.getRentSlotNo() + YesOrNoEnum.YES.getCode() + salt;
                url = "http://" + service + ":" + port + "/dev/popup";
            } else {
                // 正常方式租借
                before = sn + borrowId + salt;
                url = "http://" + service + ":" + port + "/dev/borrow";
            }
            requestObj.put("orderId", borrowId);
            requestObj.put("sign", Md5Utils.hash(before));
            String responseStr = HttpClientJSONUtil.postJSONUTF8(url, JSON.toJSONString(requestObj));
            result = JSON.parseObject(responseStr, BatteryJSONResult.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (result == null) {
            // 发送租借请求失败，则租借失败
            Used usedUpdate = new Used();
            usedUpdate.setId(usedId);
            usedUpdate.setLeaseState(LeaseStateEnum.FAIL.getCode()); // 租借失败
            usedMapper.updateByPrimaryKeySelective(usedUpdate);
            return BatteryJSONResult.errorMsg("租借失败");
        }

        if (result.getCode() == 200) {
            // 发送租借命令成功

            // TODO 对押金订单进行标记
            Order orderUpdate = new Order();
            orderUpdate.setId(noUsedDeposit.getId());
            orderUpdate.setIsDepositSign(YesOrNoEnum.YES.getCode());
            orderMapper.updateByPrimaryKeySelective(orderUpdate);

            JSONObject responseData = new JSONObject();
            responseData.put("used_id", usedId);
            responseData.put("sn", sn);
            return BatteryJSONResult.ok(responseData);
        } else {
            // 发送租借请求失败，则租借失败
            Used usedUpdate = new Used();
            usedUpdate.setId(usedId);
            usedUpdate.setLeaseState(LeaseStateEnum.FAIL.getCode()); // 租借失败
            usedMapper.updateByPrimaryKeySelective(usedUpdate);
            return BatteryJSONResult.errorMsg(result.getMsg()); // 返回租借失败信息
        }
    }


    /**
     * 获取设备套餐内容
     *
     * @param storeInstall
     * @param amount
     * @return
     */
    private String getDevMealContent(StoreInstall storeInstall, BigDecimal amount) {
        String mealMsg = "";
        String freeMsg = "";
        if (storeInstall == null) {
            freeMsg = "前2分钟内免费,";
            BigDecimal price = new BigDecimal(2);
            mealMsg = mealMsg + freeMsg + price + "元/小时,日封20元,总封" + amount + "元";
        } else {
            if (storeInstall.getFreeM() > 0) {
                freeMsg = storeInstall.getFreeM() + "分钟内免费,";
            }
            if (DevMealTimeEnum.HALF_HOUR.type.intValue() == storeInstall.getUnitTime().intValue()) {
                mealMsg = mealMsg + freeMsg + storeInstall.getPrice() + "元/半小时,日封" + storeInstall.getDayMax() + "元,总封" + amount + "元";
            } else if (DevMealTimeEnum.FIFTEEN_MINUTES.type.intValue() == storeInstall.getUnitTime().intValue()) {
                mealMsg = mealMsg + freeMsg + storeInstall.getPrice() + "元/15分钟,日封" + storeInstall.getDayMax() + "元,总封" + amount + "元";
            } else {
                mealMsg = mealMsg + freeMsg + storeInstall.getPrice() + "元/小时,日封" + storeInstall.getDayMax() + "元,总封" + amount + "元";
            }
        }
        return mealMsg;
    }

    /**
     * WS设备押金租借，方式一，（传统方式租借）
     *
     * @param noUsedDeposit
     * @param appUser
     * @param storeInstall
     * @param device
     * @return
     */
    @Transactional
    @Override
    public BatteryJSONResult wsDevTips1DepositBorrowBattery(Order noUsedDeposit, AppUser appUser, StoreInstall storeInstall, Device device) {

        String sn = device.getSn();
        Prorely prorely = prorelyMapper.selectBySn(sn);
        if (prorely == null) {
            return BatteryJSONResult.errorMsg("设备【" + sn + "】租借依据不存在");
        }

        // TODO 计算当前该笔订单是否需要M
        int isM = 0;
        PartnerInstall partnerInstall = partnerInstallMapper.selectByPrimaryKey(device.getPartnerId());
        if (appUser.getIsFree() == 0) {
            isM = Mutils.isM(partnerInstall.getBorrowCount(), partnerInstall.getmBl());
        }

        // 获取到WS设备的最新库存信息
        String usedId = sid.nextShort();
        Date date = DateUtils.getNowDate();

        Used used = new Used();
        used.setId(usedId);
        used.setChannel(appUser.getUserType());// 订单渠道 微信 1 支付宝 2
        used.setOrderNumber(GenerateSeqUtil.generateSeqNo()); // order_number
        used.setBorrowMode(BorrowModeEnum.DEPOSIT.type); // 押金租借
        used.setProjectId(device.getProjectId()); // 平台-项目ID
        used.setPartnerId(device.getPartnerId()); // 合作商
        used.setMerchantId(device.getMerchantId()); // 商户
        used.setStoreId(device.getStoreId());
        used.setAppUserId(appUser.getId());
        used.setCreateTime(date);
        used.setFalseOrderId(noUsedDeposit.getId()); // 押金租借专用

        String storeName = "";
        if (storeInstall == null) {
            // 门店信息为空，该设备未部署
            storeName = "";
        } else {
            Store store = storeMapper.selectByPrimaryKey(storeInstall.getStoreId());
            if (store != null) {
                storeName = store.getStoreName();
            }
        }
        used.setStoreName(storeName);
        Project project = projectMapper.selectByPrimaryKey(device.getProjectId());
        used.setMealContent(getDevMealContent(storeInstall, project.getDeposit()));
        used.setIsM(isM);
        used.setIsActivity(checkDevIsActivity(device, date)); // 校验该设备是否满足要求
        used.setIsFree(appUser.getIsFree()); // VIP订单
        usedMapper.insertSelective(used);


        // TODO 记录租借次数
        PartnerInstall partnerInstall1Update = new PartnerInstall();
        partnerInstall1Update.setPartnerId(partnerInstall.getPartnerId());
        partnerInstall1Update.setBorrowCount(partnerInstall.getBorrowCount() + 1);
        partnerInstallMapper.updateByPrimaryKeySelective(partnerInstall1Update);

        UsedBasics basics = new UsedBasics();
        basics.setUsedId(usedId);
        basics.setRentDate(date);
        basics.setRentDeviceId(device.getId());
        basics.setRentDeviceSn(sn);
        basics.setDevType(device.getDevType());

        String borrowId = WsDevUtils.getWsBorrowId();
        // 非强弹租借，正常方式租借
        basics.setLeaseId("borrow" + "_" + sn + "_" + borrowId); // TODO TODO 注意，以timestamp作为租借ID 要考虑
        // 保存
        usedBasicsMapper.insertUsedBasics(basics);
        BatteryJSONResult result = null;
        try {
            String service = prorely.getService();
            int port = prorely.getPort() + 100;

            String salt = Constants.ws_borrow_slat; // 加密盐
            JSONObject requestObj = new JSONObject();
            requestObj.put("sn", device.getSn());
            String before = "";
            String url = "";
            // 正常方式租借
            before = sn + borrowId + salt;
            url = "http://" + service + ":" + port + "/dev/borrow";
            requestObj.put("orderId", borrowId);
            requestObj.put("sign", Md5Utils.hash(before));
            String responseStr = HttpClientJSONUtil.postJSONUTF8(url, JSON.toJSONString(requestObj));
            result = JSON.parseObject(responseStr, BatteryJSONResult.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (result == null) {
            // 发送租借请求失败，则租借失败
            Used usedUpdate = new Used();
            usedUpdate.setId(usedId);
            usedUpdate.setLeaseState(LeaseStateEnum.FAIL.getCode()); // 租借失败
            usedMapper.updateByPrimaryKeySelective(usedUpdate);
            return BatteryJSONResult.errorMsg("租借失败");
        }

        if (result.getCode() == 200) {
            // 发送租借命令成功
            // TODO 对押金订单进行标记
            Order orderUpdate = new Order();
            orderUpdate.setId(noUsedDeposit.getId());
            orderUpdate.setIsDepositSign(YesOrNoEnum.YES.getCode());
            orderMapper.updateByPrimaryKeySelective(orderUpdate);

            JSONObject responseData = new JSONObject();
            responseData.put("used_id", usedId);
            responseData.put("sn", sn);
            return BatteryJSONResult.ok(responseData);
        } else {
            // 发送租借请求失败，则租借失败
            Used usedUpdate = new Used();
            usedUpdate.setId(usedId);
            usedUpdate.setLeaseState(LeaseStateEnum.FAIL.getCode()); // 租借失败
            usedMapper.updateByPrimaryKeySelective(usedUpdate);
            return BatteryJSONResult.errorMsg(result.getMsg()); // 返回租借失败信息
        }
    }

    /**
     * 线租借
     *
     * @param order   支付订单信息
     * @param appUser 用户信息
     * @param device  设备信息
     * @return
     */
    @Transactional
    @Override
    public JSONObject lineBorrow(Order order, AppUser appUser, Device device) {

        // 获取到WS设备的最新库存信息
        String usedId = sid.nextShort();

        Date date = DateUtils.getNowDate();

        Used used = new Used();
        used.setId(usedId);
        used.setChannel(appUser.getUserType());// 订单渠道 微信 1 支付宝 2
        used.setOrderNumber(GenerateSeqUtil.generateSeqNo()); // order_number
        used.setBorrowMode(BorrowModeEnum.LINE.type); // 线租借
        used.setProjectId(device.getProjectId()); // 平台-项目ID
        used.setPartnerId(device.getPartnerId()); // 合作商
        used.setMerchantId(device.getMerchantId()); // 商户
        used.setStoreId(device.getStoreId());
        used.setAppUserId(appUser.getId());
        used.setCreateTime(date);
        used.setLeaseState(LeaseStateEnum.SUCCESS.getCode()); // 租借成功
        used.setIsBack(YesOrNoEnum.YES.getCode()); // 归还成功
        used.setStatus(UsedStatusEnum.PAID.getCode()); // 已支付
        used.setTrueOrderId(order.getId());

        used.setAmountPaid(order.getTotalFee()); // 租借费用
        used.setDiscountAmount(BigDecimal.ZERO); // 优惠金额
        used.setPaymentTime(order.getPayTime()); // 支付时间


        Store store = storeMapper.selectByPrimaryKey(device.getStoreId());
        String storeName = "";
        if (store != null) {
            storeName = store.getStoreName();
        }
        used.setStoreName(storeName);

        int time = Integer.parseInt(order.getExtend());

        used.setMealContent(RLineUtils.getLineMeal(order.getExtend(), order.getTotalFee())); // 线租借套餐名称

        String password = getPwByNewLine(device.getId(), order.getExtend());
        used.setPassword(password);
        used.setIsActivity(checkDevIsActivity(device, date)); // 校验该设备是否满足要求

        used.setUsingTime((time * 60) + ""); // TODO 计算使用时间 以秒为单位

        used.setIsFree(appUser.getIsFree()); // VIP订单
        usedMapper.insertSelective(used);

        // 保存订单信息
        Order orderUpdate = new Order();
        orderUpdate.setId(order.getId());
        orderUpdate.setUsedId(usedId);
        orderMapper.updateByPrimaryKeySelective(orderUpdate);

        UsedBasics basics = new UsedBasics();
        basics.setUsedId(usedId);
        basics.setRentDate(date);
        basics.setBackDate(DateUtils.addMinutes(date, time)); // 记录归还时间
        basics.setIsBack(YesOrNoEnum.YES.getCode());
        basics.setDevType(DevTypeEnum.R_LINE.getCode()); // 保存线类型
        basics.setRentDeviceId(device.getId());
        basics.setRentDeviceSn(device.getSn());
        basics.setBackDeviceId(device.getId());
        basics.setBackDeviceSn(device.getSn());
        usedBasicsMapper.insertUsedBasics(basics);

        // TODO TODO 开启分成操作
        try {
            incomeService.shareMoney(used.getId(), order.getId());
        } catch (Exception e) {
            e.printStackTrace();
        }

        JSONObject object = new JSONObject();
        object.put("used_id", used.getId());
        object.put("sn", device.getSn());
        object.put("password", password);
        return object;
    }


    /**
     * 获取线密码 (R_ 线)
     *
     * @param deviceId
     * @param LineTime
     * @return
     */
    @Override
    public String getPwByNewLine(String deviceId, String LineTime) {
        Device device = deviceMapper.selectDeviceById(deviceId);
        String linePass = "";
        String sn = device.getSn();
        Integer loop = device.getNote();
        if (loop == 40) {
            loop = 1;
        }
        String numberStr = String.format("%02d", loop);
        String format = "%s%s%s";

        Example example = new Example(SysConfig.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("configKey", "sys.rline.salt");
        SysConfig config = configMapper.selectOneByExample(example);
        String salt = config.getConfigValue();
        String str = String.format(format, salt, sn, numberStr);
        String sign = Md5Utils.hash(str);
        long dec_num1 = Long.parseLong(sign.substring(28, 30), 16);
        long dec_num2 = Long.parseLong(sign.substring(30, 32), 16);
        String s1 = String.valueOf((dec_num1 & 0x3) + 1);
        String s2 = String.valueOf(((dec_num2 >> 6) & 0x3) + 1);
        String s3 = String.valueOf(((dec_num2 >> 4) & 0x3) + 1);
        String s4 = String.valueOf(((dec_num2 >> 2) & 0x3) + 1);
        String s5 = String.valueOf((dec_num2 & 0x3) + 1);
        String out = "";
        if (RLineMealTimeEnum.ONE_HOUR.type.equals(LineTime)) {
            out = "1";
        } else if (RLineMealTimeEnum.THREE_HOUR.type.equals(LineTime)) {
            out = "2";
        } else if (RLineMealTimeEnum.FIVE_HOUR.type.equals(LineTime)) {
            out = "3";
        } else if (RLineMealTimeEnum.TWELVE_HOUR.type.equals(LineTime)) {
            out = "4";
        }
        linePass = s1 + s2 + s3 + s4 + s5 + out;
        loop = loop + 1;
        Device device_ = new Device();
        device_.setNote(loop);
        device_.setId(device.getId());
        deviceMapper.updateByPrimaryKeySelective(device_);
        return linePass;
    }

    /**
     * 免押租借共享充电宝，--- （强弹方式租借+传统方式租借）
     *
     * @param authUsed     授权订单
     * @param appUser      用户信息
     * @param storeInstall 门店设置信息
     * @param device       设备信息
     * @return
     */
    @Transactional
    @Override
    public BatteryJSONResult wsDevTips2FreeDepositBorrowBattery(AuthUsed authUsed, AppUser appUser, StoreInstall storeInstall, Device device) {

        Date date = DateUtils.getNowDate();

        String sn = device.getSn();
        Prorely prorely = prorelyMapper.selectBySn(sn);
        if (prorely == null) {
            return BatteryJSONResult.errorMsg("设备【" + sn + "】租借依据不存在");
        }

        // TODO 计算当前该笔订单是否需要M
        int isM = 0;
        PartnerInstall partnerInstall = partnerInstallMapper.selectByPrimaryKey(device.getPartnerId());
        if (appUser.getIsFree() == 0) {
            isM = Mutils.isM(partnerInstall.getBorrowCount(), partnerInstall.getmBl());
        }


        Used usedUpdate = new Used();
        usedUpdate.setId(authUsed.getUsedId());
        String storeName = "";
        if (storeInstall == null) {
            // 门店信息为空，该设备未部署
            storeName = "";
        } else {
            Store store = storeMapper.selectByPrimaryKey(storeInstall.getStoreId());
            if (store != null) {
                storeName = store.getStoreName();
            }
        }
        usedUpdate.setStoreName(storeName);
        Project project = projectMapper.selectByPrimaryKey(device.getProjectId());
        usedUpdate.setMealContent(getDevMealContent(storeInstall, project.getDeposit()));
        usedUpdate.setIsM(isM);
        usedUpdate.setIsActivity(checkDevIsActivity(device, date)); // 校验该设备是否满足要求
        usedMapper.updateByPrimaryKeySelective(usedUpdate);

        // TODO 记录租借次数
        PartnerInstall partnerInstall1Update = new PartnerInstall();
        partnerInstall1Update.setPartnerId(partnerInstall.getPartnerId());
        partnerInstall1Update.setBorrowCount(partnerInstall.getBorrowCount() + 1);
        partnerInstallMapper.updateByPrimaryKeySelective(partnerInstall1Update);


        UsedBasics usedBasicsUpdate = new UsedBasics();
        usedBasicsUpdate.setUsedId(authUsed.getUsedId());
        usedBasicsUpdate.setRentDate(date);
        usedBasicsUpdate.setDevType(device.getDevType());

        boolean flag = false;
        String borrowId = WsDevUtils.getWsBorrowId();
        DeviceBasics devBasics = deviceBasicsMapper.selectByPrimaryKey(device.getId());
        Date detailStockTime = devBasics.getDetailStockTime();
        if (date.getTime() - detailStockTime.getTime() < 300 * 1000) {

            // TODO 查询之前借用的电池
            String oldBatterySn = "";
            UsedBasics basics = usedBasicsMapper.selectLatelyUsedBySn(device.getSn());
            if (basics != null) {
                oldBatterySn = basics.getBatterySn();
            }
            JSONObject batteryObj = WsDevUtils.getBorrowBatteryInfo(devBasics.getDetailStock(), devBasics.getLockBatterys(), oldBatterySn, prorely.getBps(), WsDevUtils.getWsSlotNum(device.getDevType()));
            if (batteryObj != null) {
                Integer toBorrowSlot = batteryObj.getInteger("slot");
                usedBasicsUpdate.setRentSlotNo(toBorrowSlot);
                usedBasicsUpdate.setBatterySn(batteryObj.getString("batterySn"));
                usedBasicsUpdate.setLeaseId("popup" + "_" + sn + "_" + toBorrowSlot + "_" + borrowId); // TODO TODO 注意，以timestamp作为租借ID 要考虑
                flag = true;
            }
        }
        if (!flag) {
            // 非强弹租借，正常方式租借
            usedBasicsUpdate.setLeaseId("borrow" + "_" + sn + "_" + borrowId); // TODO TODO 注意，以timestamp作为租借ID 要考虑
        }
        // 保存
        usedBasicsMapper.updateByPrimaryKeySelective(usedBasicsUpdate);

        BatteryJSONResult result = null;
        try {
            String service = prorely.getService();
            Integer port = prorely.getPort() + 100;

            String salt = Constants.ws_borrow_slat; // 加密盐
            JSONObject requestObj = new JSONObject();
            requestObj.put("sn", device.getSn());
            String before = "";
            String url = "";
            if (flag) {
                // 强弹租借
                requestObj.put("slot", usedBasicsUpdate.getRentSlotNo());
                requestObj.put("charge", YesOrNoEnum.YES.getCode());
                before = sn + usedBasicsUpdate.getRentSlotNo() + YesOrNoEnum.YES.getCode() + salt;
                url = "http://" + service + ":" + port + "/dev/popup";
            } else {
                // 正常方式租借
                before = sn + borrowId + salt;
                url = "http://" + service + ":" + port + "/dev/borrow";
            }
            requestObj.put("orderId", borrowId);
            requestObj.put("sign", Md5Utils.hash(before));
            String responseStr = HttpClientJSONUtil.postJSONUTF8(url, JSON.toJSONString(requestObj));
            result = JSON.parseObject(responseStr, BatteryJSONResult.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (result == null) {
            // 发送租借请求失败，则租借失败
            Used usedUpdate2 = new Used();
            usedUpdate2.setId(authUsed.getUsedId());
            usedUpdate2.setLeaseState(LeaseStateEnum.FAIL.getCode()); // 租借失败
            usedMapper.updateByPrimaryKeySelective(usedUpdate2);
            return BatteryJSONResult.errorMsg("租借失败");
        }
        if (result.getCode().intValue() == 200) {
            // 发送租借命令成功
            JSONObject responseData = new JSONObject();
            responseData.put("used_id", authUsed.getUsedId());
            responseData.put("sn", sn);
            return BatteryJSONResult.ok(responseData);
        }
        // 发送租借请求失败，则租借失败
        Used usedUpdate2 = new Used();
        usedUpdate2.setId(authUsed.getUsedId());
        usedUpdate2.setLeaseState(LeaseStateEnum.FAIL.getCode()); // 租借失败
        usedMapper.updateByPrimaryKeySelective(usedUpdate2);
        return BatteryJSONResult.errorMsg(result.getMsg()); // 返回租借失败信息
    }

    /**
     * 免押租借共享充电宝 （传统方式租借）
     *
     * @param authUsed
     * @param appUser
     * @param storeInstall
     * @param device
     * @return
     */
    @Transactional
    @Override
    public BatteryJSONResult wsDevTips1FreeDepositBorrowBattery(AuthUsed authUsed, AppUser appUser, StoreInstall storeInstall, Device device) {

        Date date = DateUtils.getNowDate();

        String sn = device.getSn();
        Prorely prorely = prorelyMapper.selectBySn(sn);
        if (prorely == null) {
            return BatteryJSONResult.errorMsg("设备【" + sn + "】租借依据不存在");
        }


        // TODO 计算当前该笔订单是否需要M
        int isM = 0;
        PartnerInstall partnerInstall = partnerInstallMapper.selectByPrimaryKey(device.getPartnerId());
        if (appUser.getIsFree() == 0) {
            isM = Mutils.isM(partnerInstall.getBorrowCount(), partnerInstall.getmBl());
        }

        Used usedUpdate = new Used();
        usedUpdate.setId(authUsed.getUsedId());
        String storeName = "";
        if (storeInstall != null) {
            Store store = storeMapper.selectByPrimaryKey(storeInstall.getStoreId());
            if (store != null) {
                storeName = store.getStoreName();
            }
        }
        usedUpdate.setStoreName(storeName);
        Project project = projectMapper.selectByPrimaryKey(device.getProjectId());
        usedUpdate.setMealContent(getDevMealContent(storeInstall, project.getDeposit()));
        usedUpdate.setIsM(isM);
        usedUpdate.setIsActivity(checkDevIsActivity(device, date)); // 校验该设备是否满足要求
        usedMapper.updateByPrimaryKeySelective(usedUpdate);

        // TODO 记录租借次数
        PartnerInstall partnerInstall1Update = new PartnerInstall();
        partnerInstall1Update.setPartnerId(partnerInstall.getPartnerId());
        partnerInstall1Update.setBorrowCount(partnerInstall.getBorrowCount() + 1);
        partnerInstallMapper.updateByPrimaryKeySelective(partnerInstall1Update);


        UsedBasics usedBasicsUpdate = new UsedBasics();
        usedBasicsUpdate.setUsedId(authUsed.getUsedId());
        usedBasicsUpdate.setRentDate(date);
        usedBasicsUpdate.setDevType(device.getDevType());

        String borrowId = WsDevUtils.getWsBorrowId();
        usedBasicsUpdate.setLeaseId("borrow" + "_" + sn + "_" + borrowId); // TODO TODO 注意，以timestamp作为租借ID 要考虑
        // 保存
        usedBasicsMapper.updateByPrimaryKeySelective(usedBasicsUpdate);

        BatteryJSONResult result = null;
        try {
            String service = prorely.getService();
            Integer port = prorely.getPort() + 100;

            String salt = Constants.ws_borrow_slat; // 加密盐
            JSONObject requestObj = new JSONObject();
            requestObj.put("sn", device.getSn());
            String before = "";
            String url = "";
            // 正常方式租借
            before = sn + borrowId + salt;
            url = "http://" + service + ":" + port + "/dev/borrow";
            requestObj.put("orderId", borrowId);
            requestObj.put("sign", Md5Utils.hash(before));
            String responseStr = HttpClientJSONUtil.postJSONUTF8(url, JSON.toJSONString(requestObj));
            result = JSON.parseObject(responseStr, BatteryJSONResult.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (result == null) {
            // 发送租借请求失败，则租借失败
            Used usedUpdate2 = new Used();
            usedUpdate2.setId(authUsed.getUsedId());
            usedUpdate2.setLeaseState(LeaseStateEnum.FAIL.getCode()); // 租借失败
            usedMapper.updateByPrimaryKeySelective(usedUpdate);
            return BatteryJSONResult.errorMsg("租借失败");
        }
        if (result.getCode().intValue() == 200) {
            // 发送租借命令成功
            JSONObject responseData = new JSONObject();
            responseData.put("used_id", authUsed.getUsedId());
            responseData.put("sn", sn);
            return BatteryJSONResult.ok(responseData);
        }
        // 发送租借请求失败，则租借失败
        Used usedUpdate2 = new Used();
        usedUpdate2.setId(authUsed.getUsedId());
        usedUpdate2.setLeaseState(LeaseStateEnum.FAIL.getCode()); // 租借失败
        usedMapper.updateByPrimaryKeySelective(usedUpdate);
        return BatteryJSONResult.errorMsg(result.getMsg()); // 返回租借失败信息
    }


    /**
     * WS设备根据归还消息结束订单
     *
     * @param used
     * @param entity
     * @param obj_   通过心跳结束的，则里面存储的是电池信息
     * @return
     */
    @Transactional
    @Override
    public BatteryJSONResult wsDevRequestEndUsed(Used used, AliPayEntity entity, JSONObject obj_) {
        Date backDate = DateUtils.getNowDate(); // 归还时间
        Date rentDate = used.getCreateTime(); // 租借时间
        // 计算租借费用
        StoreInstall storeInstall = storeInstallMapper.selectByPrimaryKey(used.getStoreId());
        ReckonEntity reckonEntity = new ReckonEntity();
        if (storeInstall != null) {
            reckonEntity.setMealTime(storeInstall.getUnitTime());
            reckonEntity.setPrice(storeInstall.getPrice());
            reckonEntity.setFreeTime(storeInstall.getFreeM());
            reckonEntity.setDailyCapping(storeInstall.getDayMax());
            reckonEntity.setFirstTimePrice(storeInstall.getPrice());
        } else {
            // TODO 默认   2分钟免费 2元一小时，日封顶20元，总封99元
            reckonEntity.setMealTime(60);
            reckonEntity.setPrice(new BigDecimal(2));
            reckonEntity.setFreeTime(2); // 免费时间 单位为分钟
            reckonEntity.setDailyCapping(new BigDecimal(20)); // 封顶金额
            reckonEntity.setFirstTimePrice(new BigDecimal(2)); // 首小时价格
        }

        Project project = projectMapper.selectByPrimaryKey(used.getProjectId());
        BigDecimal deposit = new BigDecimal(99);
        if (project != null) {
            deposit = project.getDeposit();
        }

        // 计算得出原价
        BigDecimal costPrice = ReckonUtils.reckonCostPrice(reckonEntity, backDate, rentDate, deposit);

        // 判断用户是否VIP
        UsedBasics usedBasics = usedBasicsMapper.selectByPrimaryKey(used.getId());
        String borrowSn = usedBasics.getRentDeviceSn(); // 租借机柜SN
        Device borrowDev = deviceMapper.selectByPrimaryKey(usedBasics.getRentDeviceId()); // 借出机柜信息

        String backDevId = "";
        String backSn = "";
        if (obj_ != null) {
            backDevId = obj_.getString("deviceId"); // 归还的设备ID
            backSn = obj_.getString("backSn"); // 归还的机柜SN
            String slot = obj_.getString("slot"); // 归还的机柜SN
            // 心跳结束的订单，将对应的电池信息存储到租借记录中
            UsedBasics basicsUpdate = new UsedBasics();
            basicsUpdate.setUsedId(used.getId());
            basicsUpdate.setBackDeviceId(backDevId);
            basicsUpdate.setBackDeviceSn(backSn); // 归还设备sn
            basicsUpdate.setBackSlotNo(Integer.parseInt(slot)); // 归还的设备槽位
            usedBasicsMapper.updateByPrimaryKeySelective(basicsUpdate);
        } else {
            backDevId = usedBasics.getBackDeviceId();
            backSn = usedBasics.getBackDeviceSn();
        }

        BigDecimal actualMoney = null;  // 实付金额
        AppUser appUser = appUserMapper.selectByPrimaryKey(used.getAppUserId());
        if (appUser.getIsFree().intValue() == YesOrNoEnum.YES.getCode() && costPrice.compareTo(BigDecimal.ZERO) > 0 && costPrice.subtract(deposit).compareTo(BigDecimal.ZERO) != 0) {
            // 是VIP , 判断是否为超级VIp
            boolean flag = false; // 是否优惠

            String devSn = null;
            Example example = new Example(Member.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("appUserId", used.getAppUserId());
            criteria.andEqualTo("auditStatus", 1); // 审核通过的VIP
            criteria.andEqualTo("isDelete", YesOrNoEnum.NO.getCode());
            Member member = memberMapper.selectOneByExample(example);
            if (member != null) {
                if (YesOrNoEnum.NO.getCode().intValue() == member.getIsSuper().intValue()) {
                    // 是普通VIP,需要判断租借机柜SN
//                if (borrowSn.equals(member.getDevSn())) {
                    if (borrowDev != null && member.getStoreId().equals(borrowDev.getStoreId())) {
                        // 该VIP用户租借的是可免费的机柜，那么开始计算其的优惠金额
                        // 首先查询该VIP用户的租借次数
                        flag = true;
                    }
                } else {
                    // 是超级VIP, 对所有设备都可进行免费
                    flag = true;
                }
            }
            if (flag) {
                Integer dailyOrderLimit = member.getDailyOrderLimit(); // 每天免费订单数
                if (dailyOrderLimit > 0) {
                    // 查询该VIP用户今日已免费次数
                    Integer todayFreeCount = usedMapper.selectCountByTodayFree(appUser.getId());
                    if (todayFreeCount < dailyOrderLimit) {
                        // 今天用户已免费次数 小于等于 VIP用户的设置的免费次数
                        // 可以优惠
                        Integer orderFreeMinute = member.getOrderFreeMinute(); // 可免费时间段
                        // 计算得出该VIP用户需要支付的金额
                        Long freeTime = Long.valueOf(orderFreeMinute * 60 * 1000);

                        Long diffTime = backDate.getTime() - rentDate.getTime() - freeTime;
                        if (diffTime <= 0) {
                            // 计算得出时间小于0，在免费时间内归还
                            actualMoney = BigDecimal.ZERO;
                        } else {
                            actualMoney = ReckonUtils.reckonTimeDiffMoney(reckonEntity, diffTime, project.getDeposit());
                        }
                    }
                }
            }
        }

        BigDecimal needPay = BigDecimal.ZERO;
        // 将租借状态设置为租借成功
        Used usedUpdate = new Used();
        usedUpdate.setId(used.getId());
        usedUpdate.setIsBack(YesOrNoEnum.YES.getCode());

        // 将归还信息存储到租借记录里面
        Device backDevice = deviceMapper.selectByPrimaryKey(backDevId);
        if (backDevice != null) {
            Store store = storeMapper.selectByPrimaryKey(backDevice.getStoreId());
            String storeName = "";
            if (store != null) {
                storeName = store.getStoreName();
            }
            usedUpdate.setReturnStore(storeName);
        }
        if (actualMoney == null) {
            // 不是VIP用户，那么该用户的实付金额为 原价
            usedUpdate.setAmountPaid(costPrice);
            usedUpdate.setDiscountAmount(BigDecimal.ZERO);
            needPay = costPrice;
        } else {
            // 是VIP用户，且存在优惠金额
            usedUpdate.setAmountPaid(actualMoney);
            usedUpdate.setDiscountAmount(costPrice.subtract(actualMoney));
            usedUpdate.setIsFree(YesOrNoEnum.YES.getCode()); // VIP 用户订单
            needPay = actualMoney;
        }

        boolean isZero = false;
        if (needPay.subtract(BigDecimal.ZERO).compareTo(BigDecimal.ZERO) == 0) {
            // 租借金额为0,直接设置为已支付
            usedUpdate.setStatus(UsedStatusEnum.PAID.getCode());
            usedUpdate.setPaymentTime(backDate);
            isZero = true;
        }
//        usedUpdate.setUsingTime(DateUtils.getDateMin(backDate, rentDate) + ""); // 计算使用时间
        usedUpdate.setUsingTime(DateUtils.getDateSecond(backDate, rentDate) + ""); // TODO 计算使用时间 以秒为单位
        usedMapper.updateByPrimaryKeySelective(usedUpdate);

        UsedBasics basicsUpdate = new UsedBasics();
        basicsUpdate.setUsedId(used.getId());
        basicsUpdate.setIsBack(YesOrNoEnum.YES.getCode());
        basicsUpdate.setBackDate(backDate);
        usedBasicsMapper.updateByPrimaryKeySelective(basicsUpdate);
        // 开始进行扣费
        Integer channel = used.getChannel();
        Integer borrow_mode = used.getBorrowMode();
        if (isZero) {
            // 租借费用为0元，且
            if (borrow_mode == BorrowModeEnum.DEPOSIT.type.intValue()) {
                // 押金租借
                // TODO TODO 这里进行自动退押金操作
//                int autoRefundYj = Integer.parseInt(configService.selectConfigByKeyNoCache("sys.borrow.autoRefundYj"));
//                if (autoRefundYj == 1) {
                // 自动退押金
                if (UserTypeEnum.WX.getCode().intValue() == channel.intValue()) {
                    // 微信自动退押金
                    return autoZeroRefundWxDeposit(used, appUser);
                } else {
                    // 支付宝自动退押金
                    return autoZeroRefundAliDeposit(used, appUser, entity);
                }
//                }
            }
            // 免押租借0元结束
            if (UserTypeEnum.WX.getCode().intValue() == channel.intValue()) {
                // 微信支付分0元结束
                return completeWxUsed(used.getId());
            } else {
                // 支付宝预授权0元结束
                // 若存在 0 租金订单，可调用解冻接口实现 0 租金订单，具体查看 解冻接口
                return unfreezeToZero(used.getId(), entity);
            }
        }
        // 押金租借，非零元
        if (borrow_mode == BorrowModeEnum.DEPOSIT.type.intValue()) {
            if (UserTypeEnum.WX.getCode().intValue() == channel.intValue()) {
                // 微信
                return depositWxEndUsed(used.getId(), backDate);
            } else {
                // 支付宝
                return depositAliEndUsed(used.getId(), entity, backDate);
            }
        }
        if (UserTypeEnum.WX.getCode().intValue() == channel.intValue()) {
            // 微信租借，判断是押金租借，还是免押租借
            return completeWxUsed(used.getId());
        } else {
            // 支付宝预授权，授权转支付
            return freezeToPay(used.getId(), entity);
        }
    }


    /**
     * 支付宝用户---自动退押金操作
     *
     * @param used
     * @param appUser
     * @return
     */
    private BatteryJSONResult autoZeroRefundAliDeposit(Used used, AppUser appUser, AliPayEntity entity) {
        Order orderDeposit = orderMapper.selectByPrimaryKey(used.getFalseOrderId());
        if (orderDeposit != null) {
            BigDecimal refund_fee = orderDeposit.getTotalFee(); // TODO 注意：全额退押金
            Example example = new Example(RefundOrder.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("orderId", orderDeposit.getId());
            criteria.andEqualTo("refundStatus", RefundStatusEnum.CHANGE.getCode()); // 退款异常
            RefundOrder errRefund = refundOrderMapper.selectOneByExample(example);

            String out_refund_no = ""; // 退款单号
            String refundOrderId = null;
            if (errRefund != null) {
                // 存在退款异常的订单
                // 存在错误的退款订单，那么采用错误的退款订单来进行操作
                out_refund_no = errRefund.getOutRefundNo();
                RefundOrder orderUpdate = new RefundOrder();
                orderUpdate.setId(errRefund.getId());
                orderUpdate.setRefundFee(refund_fee);
                orderUpdate.setRefundStatus(RefundStatusEnum.REQUEST_REFUND.getCode()); // 发起退款
                refundOrderMapper.updateByPrimaryKeySelective(orderUpdate);

                refundOrderId = errRefund.getId();
            } else {
                out_refund_no = GenerateSeqUtil.generateEndRadomCode() + GenerateSeqUtil.getRandomCode(6);
                RefundOrder refundOrder = new RefundOrder();
                refundOrder.setId(sid.nextShort());
                refundOrder.setAppUserId(appUser.getId());
                refundOrder.setOutRefundNo(out_refund_no);
                refundOrder.setTotalFee(orderDeposit.getTotalFee());
                refundOrder.setRefundFee(refund_fee);
                refundOrder.setRefundDesc("自动退押金");
                refundOrder.setRefundStatus(RefundStatusEnum.REQUEST_REFUND.getCode()); // 发起退款
                refundOrder.setCreateTime(DateUtils.getNowDate());
                refundOrder.setOrderId(orderDeposit.getId());
                refundOrder.setOrderType(orderDeposit.getOrderType());
                refundOrder.setChannel(orderDeposit.getChannel());
                refundOrderMapper.insertSelective(refundOrder);

                // 查询新建的退款数据
                refundOrderId = refundOrder.getId();
            }
            // 发起退款操作
            JSONObject requestRefundObj = new JSONObject();
            requestRefundObj.put("out_trade_no", orderDeposit.getOutOrderNo());
            requestRefundObj.put("trade_no", orderDeposit.getTransactionId());
            requestRefundObj.put("out_request_no", out_refund_no);
            requestRefundObj.put("refund_amount", refund_fee);
            BatteryJSONResult result = null;
            boolean flag = false;
            try {
                result = AliPayUtils.tradeRefund(entity, requestRefundObj);
            } catch (Exception e) {
                e.printStackTrace();
                flag = true;
            }
            if (result == null || flag) {
                // 支付宝退款抛出异常
                RefundOrder updateRefundOrder = new RefundOrder();
                updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
                updateRefundOrder.setId(refundOrderId);
                updateRefundOrder.setRemark("发起退押出现异常");
                refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);
                return BatteryJSONResult.errorMsg("发起退押出现异常");
            }
            AlipayTradeRefundResponse response = (AlipayTradeRefundResponse) result.getData();
            if (response.isSuccess()) {
                // 退款成功
                RefundOrder updateOrder = new RefundOrder();
                updateOrder.setId(refundOrderId);
                updateOrder.setRefundStatus(RefundStatusEnum.SUCCESS.getCode());
                updateOrder.setSuccessTime(DateUtils.getNowDate());
                refundOrderMapper.updateByPrimaryKeySelective(updateOrder);

                // 更新原先订单状态
                Order updateFormer = new Order();
                updateFormer.setId(orderDeposit.getId());
                updateFormer.setTradeState(OrderTradeStateEnum.REFUND_SUCCESS.getCode()); // 直接更新状态为退款成功
                updateFormer.setRefundId(out_refund_no); // 退款订单号
                updateFormer.setRefundMoney(refund_fee); // 退款金额
                orderMapper.updateByPrimaryKeySelective(updateFormer);

                return BatteryJSONResult.ok();
            }
            RefundOrder updateRefundOrder = new RefundOrder();
            updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
            updateRefundOrder.setId(refundOrderId);
            updateRefundOrder.setRemark("发起退押出现异常");
            refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);
            return BatteryJSONResult.errorMsg("退押失败,支付宝返回【" + response.getSubMsg() + "】"); // 返回错误描述
        }
        return BatteryJSONResult.ok();
    }


    /**
     * 微信用户---自动退押金操作
     *
     * @param used
     * @param appUser
     * @return
     */
    private BatteryJSONResult autoZeroRefundWxDeposit(Used used, AppUser appUser) {
        Order orderDeposit = orderMapper.selectByPrimaryKey(used.getFalseOrderId());
        if (orderDeposit != null) {
            BigDecimal refund_fee = orderDeposit.getTotalFee(); // TODO 注意：全额退押金
            // 存在对应的押金
            // 查询该笔押金是否已存在对应的退款订单
            Example example = new Example(RefundOrder.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("orderId", orderDeposit.getId());
            criteria.andEqualTo("refundStatus", RefundStatusEnum.CHANGE.getCode()); // 退款异常
            RefundOrder errRefund = refundOrderMapper.selectOneByExample(example);
            String out_refund_no = ""; // 退款单号
            String refundOrderId = null;
            if (errRefund != null) {
                // 存在退款异常的订单
                // 存在错误的退款订单，那么采用错误的退款订单来进行操作
                out_refund_no = errRefund.getOutRefundNo();
                RefundOrder orderUpdate = new RefundOrder();
                orderUpdate.setId(errRefund.getId());
                orderUpdate.setRefundFee(refund_fee);
                orderUpdate.setRefundStatus(RefundStatusEnum.REQUEST_REFUND.getCode()); // 发起退款
                refundOrderMapper.updateByPrimaryKeySelective(orderUpdate);
                refundOrderId = errRefund.getId();
            } else {
                // 退款单号
                out_refund_no = GenerateSeqUtil.generateEndRadomCode() + GenerateSeqUtil.getRandomCode(6);
                RefundOrder refundOrder = new RefundOrder();
                refundOrder.setId(sid.nextShort());
                refundOrder.setAppUserId(appUser.getId());
                refundOrder.setOutRefundNo(out_refund_no);
                refundOrder.setTotalFee(orderDeposit.getTotalFee());
                refundOrder.setRefundFee(refund_fee);
                refundOrder.setRefundDesc("自动退押金");
                refundOrder.setRefundStatus(RefundStatusEnum.REQUEST_REFUND.getCode()); // 发起退款
                refundOrder.setCreateTime(DateUtils.getNowDate());
                refundOrder.setOrderId(orderDeposit.getId());
                refundOrder.setOrderType(orderDeposit.getOrderType());
                refundOrder.setChannel(orderDeposit.getChannel());
                refundOrderMapper.insertSelective(refundOrder);

                // 查询新建的退款数据
                refundOrderId = refundOrder.getId();
            }
            // 发起退款操作
            WxPayRefundRequest refundRequest = new WxPayRefundRequest();
            refundRequest.setTransactionId(orderDeposit.getTransactionId());
            refundRequest.setOutRefundNo(out_refund_no);
            refundRequest.setTotalFee(orderDeposit.getTotalFee().multiply(new BigDecimal(100)).intValue());
            refundRequest.setRefundFee(refund_fee.multiply(new BigDecimal(100)).intValue());
            refundRequest.setNotifyUrl(Constants.wx_refund_callback_url); // 退款通知接口
            WxPayRefundResult refundResult = null;
            boolean flag = false;
            try {
                refundResult = wxService.refund(refundRequest);
            } catch (WxPayException e) {
                // 发生错误
                e.printStackTrace();
                flag = true;
            }

            if (refundResult == null || flag) {
                // 调起微信退款接口发生错误
                RefundOrder updateRefundOrder = new RefundOrder();
                updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
                updateRefundOrder.setId(refundOrderId);
                updateRefundOrder.setRemark("发起退押出现异常");
                refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);

                return BatteryJSONResult.errorMsg("发起退押出现异常");
            }
            String return_code = refundResult.getReturnCode();
            String result_code = refundResult.getResultCode();
            if ("SUCCESS".equals(return_code) && "SUCCESS".equals(result_code)) {
                // 发起退款接口成功，更新退款订单号
                String refund_id = refundResult.getRefundId(); // 微信退款单号
                RefundOrder updateOrder = new RefundOrder();
                updateOrder.setId(refundOrderId);
                updateOrder.setRefundId(refund_id);
                refundOrderMapper.updateRefundOrder(updateOrder);

                // 更新原先订单状态
                Order updateFormer = new Order();
                updateFormer.setId(orderDeposit.getId());
                updateFormer.setTradeState(OrderTradeStateEnum.TO_REFUND.getCode()); // 转入退款
                updateFormer.setRefundId(out_refund_no); // 退款订单号
                updateFormer.setRefundMoney(refund_fee); // 退款金额
                updateFormer.setUsedId(used.getId());
                orderMapper.updateByPrimaryKeySelective(updateFormer);
                return BatteryJSONResult.ok();
            }
            // 调起微信退款接口发生错误
            RefundOrder updateRefundOrder = new RefundOrder();
            updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
            updateRefundOrder.setId(refundOrderId);
            updateRefundOrder.setRemark("发起退押出现异常");
            refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);
            return BatteryJSONResult.errorMsg("退押失败,微信返回【" + refundResult.getErrCodeDes() + "】"); // 返回错误描述
        }
        return BatteryJSONResult.ok();
    }


    /**
     * 后台结束订单
     *
     * @param usedUpdate 需更新数据
     * @param entity
     * @return
     */
    @Transactional
    @Override
    public AjaxResult backstageEndUsed(Used usedUpdate, AliPayEntity entity) {

        Date backDate = DateUtils.getNowDate(); // 归还时间
        BigDecimal needPay = usedUpdate.getAmountPaid();

        usedUpdate.setIsBack(YesOrNoEnum.YES.getCode());
        usedUpdate.setAmountPaid(needPay);
        usedUpdate.setDiscountAmount(BigDecimal.ZERO);

        boolean isZero = false;
        if (needPay.subtract(BigDecimal.ZERO).compareTo(BigDecimal.ZERO) == 0) {
            // 零元订单结束
            usedUpdate.setStatus(UsedStatusEnum.PAID.getCode());
            usedUpdate.setPaymentTime(backDate);
            isZero = true;
        }
        usedMapper.updateByPrimaryKeySelective(usedUpdate);

        UsedBasics basicsUpdate = new UsedBasics();
        basicsUpdate.setUsedId(usedUpdate.getId());
        basicsUpdate.setIsBack(YesOrNoEnum.YES.getCode());
        basicsUpdate.setBackDate(backDate);
        usedBasicsMapper.updateByPrimaryKeySelective(basicsUpdate);

        Used used = usedMapper.selectByPrimaryKey(usedUpdate.getId());

        Integer channel = used.getChannel();
        Integer borrow_mode = used.getBorrowMode();
        if (isZero) {
            // 租借费用为0元，且
            if (borrow_mode == BorrowModeEnum.DEPOSIT.type) {
                // 押金租借
//                int autoRefundYj = Integer.parseInt(configService.selectConfigByKeyNoCache("sys.borrow.autoRefundYj"));
//                if (autoRefundYj == 1) {
                // TODO TODO 自动退押金
                AppUser appUser = appUserMapper.selectByPrimaryKey(used.getAppUserId());
                if (UserTypeEnum.WX.getCode().intValue() == channel.intValue()) {
                    // TODO 微信
                    BatteryJSONResult result = autoZeroRefundWxDeposit(used, appUser);
                    if (result != null && result.getCode() == 0) {
                        // 自动退押失败
                        return AjaxResult.error(result.getMsg());
                    }
                } else {
                    // TODO 支付宝
                    BatteryJSONResult result = autoZeroRefundAliDeposit(used, appUser, entity);
                    if (result != null && result.getCode() == 0) {
                        // 自动退押失败
                        return AjaxResult.error(result.getMsg());
                    }
                }
//                }
                return AjaxResult.success();
            }
            // 免押租借0元结束
            if (UserTypeEnum.WX.getCode().intValue() == channel.intValue()) {
                // 微信支付分0元结束
                BatteryJSONResult result = completeWxUsed(used.getId());
                if (result.getCode() == 1) {
                    return AjaxResult.success();
                } else {
                    return AjaxResult.error(result.getMsg());
                }
            } else {
                // 支付宝预授权0元结束
                BatteryJSONResult result = unfreezeToZero(used.getId(), entity);
                if (result.getCode() == 1) {
                    return AjaxResult.success();
                } else {
                    return AjaxResult.error(result.getMsg());
                }
            }
        }

        // 押金租借，非零元
        if (borrow_mode == BorrowModeEnum.DEPOSIT.type.intValue()) {
//            BatteryJSONResult result = depositEndUsed(used.getId(), backDate);
//            if (result.getCode() == 1) {
//                return AjaxResult.success();
//            } else {
//                return AjaxResult.error("发生错误！");
//            }
            if (UserTypeEnum.WX.getCode().intValue() == channel.intValue()) {
                BatteryJSONResult result = depositWxEndUsed(used.getId(), backDate);
                if (result.getCode() == 1) {
                    return AjaxResult.success();
                } else {
                    return AjaxResult.error("发生错误！");
                }
            } else {
                BatteryJSONResult result = depositAliEndUsed(used.getId(), entity, backDate);
                if (result.getCode() == 1) {
                    return AjaxResult.success();
                } else {
                    return AjaxResult.error("发生错误！");
                }
            }
        }

        if (UserTypeEnum.WX.getCode().intValue() == channel.intValue()) {
            // 微信租借，判断是押金租借，还是免押租借
            BatteryJSONResult result = completeWxUsed(used.getId());
            if (result.getCode() == 1) {
                return AjaxResult.success();
            }
        } else {
            // 支付宝预授权，授权转支付
            BatteryJSONResult result = freezeToPay(used.getId(), entity);
            if (result.getCode() == 1) {
                return AjaxResult.success();
            }
        }
        return AjaxResult.error();
    }

    @Override
    public List<UsedOrder> selectUsedOrderList(Map<String, String> map) {
        return usedMapper.selectUsedOrderList(map);
    }

    @Override
    public List<UsedOrder> selectUsedDevOrderList(String devId) {
        return usedMapper.selectUsedDevOrderList(devId);
    }


    /**
     * 查询用户租借次数
     *
     * @param appUserId
     * @return
     */
    @Override
    public Integer selectBorrowCount(String appUserId) {
        Example example = new Example(Used.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("appUserId", appUserId);
        return usedMapper.selectCountByExample(example);
    }

    /**
     * 获取对应租借详情信息
     *
     * @param used_id
     * @return
     */
    @Override
    public UsedVO getUsedInfoById(String used_id) {

        Used used = usedMapper.selectByPrimaryKey(used_id);

        UsedBasics basics = usedBasicsMapper.selectByPrimaryKey(used_id);

        UsedVO usedVO = new UsedVO();
        usedVO.setId(used_id);
        usedVO.setLeaseState(used.getLeaseState());
        usedVO.setBorrowMode(used.getBorrowMode());
        usedVO.setIsBack(used.getIsBack());
        usedVO.setStatus(used.getStatus());
        usedVO.setOrderNumber(used.getOrderNumber());
        usedVO.setRentDeviceSn(basics.getRentDeviceSn());
        usedVO.setAmountPaid(used.getAmountPaid());
        usedVO.setOrderNumber(used.getOrderNumber());

        usedVO.setUsedTypeMsg("机柜订单");
        String devType = basics.getDevType();
        if (DevTypeEnum.WS_DEV_6.getCode().equals(devType)) {
            usedVO.setDevTypeMsg(DevTypeEnum.WS_DEV_6.getValue()); // 设备类型
        } else if (DevTypeEnum.WS_DEV_4.getCode().equals(devType)) {
            usedVO.setDevTypeMsg(DevTypeEnum.WS_DEV_4.getValue()); // 设备类型
        } else if (DevTypeEnum.WS_DEV_9.getCode().equals(devType)) {
            usedVO.setDevTypeMsg(DevTypeEnum.WS_DEV_9.getValue()); // 设备类型
        } else if (DevTypeEnum.WS_DEV_12.getCode().equals(devType)) {
            usedVO.setDevTypeMsg(DevTypeEnum.WS_DEV_12.getValue()); // 设备类型
        } else if (DevTypeEnum.R_LINE.getCode().equals(devType)) {
            usedVO.setDevTypeMsg(DevTypeEnum.R_LINE.getValue());
            usedVO.setUsedTypeMsg("线订单");
        } else {
            usedVO.setUsedTypeMsg("其他设备");
        }
        usedVO.setStoreName(used.getStoreName());
        usedVO.setRentDate(basics.getRentDate());
        if (used.getLeaseState().intValue() == 1) {
            // 租借成功
            Date date = DateUtils.getNowDate();
            if (used.getIsBack() == 1) {
                date = basics.getBackDate();
            }
            usedVO.setUseTime(DateUtils.getDatePoor(date, basics.getRentDate()));
        }
        usedVO.setBackDate(basics.getBackDate());
        usedVO.setMealContent(used.getMealContent());
        return usedVO;
    }


    /**
     * 获取该用户最近一个月的租借订单信息
     *
     * @param map
     * @return
     */
    @Override
    public List<UsedVO> selectListByMap(Map<String, Object> map) {
        return usedMapper.selectListByMap(map);
    }

    /**
     * 获取该用户最近一次租借次数
     *
     * @param appUserId
     * @param lastMonth
     * @return
     */
    @Override
    public Integer selectCountLastMonth(String appUserId, Date lastMonth) {

        Example example = new Example(Used.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("appUserId", appUserId);
        criteria.andGreaterThan("createTime", lastMonth);
        return usedMapper.selectCountByExample(example);
    }

    /**
     * @param map
     * @return
     */
    @Override
    public Integer selectListByMapCout(Map<String, Object> map) {
        return usedMapper.selectListByMapCout(map);
    }

    /**
     * 查询总营业收入
     *
     * @return
     */
    @Override
    public BigDecimal selectSuccessSum() {
        return usedMapper.selectSuccessSum();
    }

    @Override
    public Long selectSuccessCount() {
        return usedMapper.selectSuccessCount();
    }

    /**
     * @return
     */
    @Override
    public List<StatisticsVO> selectStatisticsVO() {
        return usedMapper.selectStatisticsVO();
    }

    /**
     * 查询最近一个月的营业额
     *
     * @return
     */
    @Override
    public BigDecimal selectSuccessSumByMouth() {
        return usedMapper.selectSuccessSumByMouth();
    }

    @Override
    public Long selectSuccessCountByMouth() {
        return usedMapper.selectSuccessCountByMouth();
    }

    /**
     * 查询该电池是否存在正在进行中的订单
     *
     * @param batterySn
     * @return
     */
    @Override
    public Used selectOneInProgressByBatterySn(String batterySn) {
        return usedMapper.selectOneInProgressByBatterySn(batterySn);
    }


    /**
     * 查询该VIP用户今日已免费次数
     *
     * @param appUserId
     * @return
     */
    @Override
    public Integer selectCountByTodayFree(String appUserId) {
        return usedMapper.selectCountByTodayFree(appUserId);
    }

    @Override
    public List<IncomeTrend> selectIncomeByTrendDay(Map<String, String> map) {
        return usedMapper.selectIncomeByTrendDay(map);
    }

    @Override
    public List<IncomeTrend> selectIncomeByTrendMonth(Map<String, String> map) {
        return usedMapper.selectIncomeByTrendMonth(map);
    }

    @Override
    public List<IncomeTrend> selectIncomeByTrendWeek(Map<String, String> map) {
        return usedMapper.selectIncomeByTrendWeek(map);
    }


    /**
     * VIP租借线
     *
     * @param appUser
     * @param device
     * @return
     */
    @Override
    public JSONObject lineVipBorrow(AppUser appUser, Device device, JSONObject meal) {

        // 获取到WS设备的最新库存信息
        String usedId = sid.nextShort();
        Date date = DateUtils.getNowDate();

        String lineTime = meal.getString("time");
        BigDecimal account = meal.getBigDecimal("amount");

        Used used = new Used();
        used.setId(usedId);
        used.setChannel(appUser.getUserType());// 订单渠道 微信 1 支付宝 2
        used.setOrderNumber(GenerateSeqUtil.generateSeqNo()); // order_number
        used.setBorrowMode(BorrowModeEnum.LINE.type); // 线租借
        used.setProjectId(device.getProjectId()); // 平台-项目ID
        used.setPartnerId(device.getPartnerId()); // 合作商
        used.setMerchantId(device.getMerchantId()); // 商户
        used.setStoreId(device.getStoreId());
        used.setAppUserId(appUser.getId());
        used.setCreateTime(date);
        used.setLeaseState(LeaseStateEnum.SUCCESS.getCode()); // 租借成功
        used.setIsBack(YesOrNoEnum.YES.getCode()); // 归还成功
        used.setStatus(UsedStatusEnum.PAID.getCode()); // 已支付
        used.setTrueOrderId(null); // 免费租借

        used.setAmountPaid(BigDecimal.ZERO);
        used.setDiscountAmount(account); // 优惠金额
        used.setPaymentTime(date); // 支付时间
        used.setIsFree(YesOrNoEnum.YES.getCode());

        int time = Integer.parseInt(lineTime);
        used.setUsingTime((time * 60) + ""); // TODO 计算使用时间 以秒为单位

        Store store = storeMapper.selectByPrimaryKey(device.getStoreId());
        String storeName = "";
        if (store != null) {
            storeName = store.getStoreName();
        }
        used.setStoreName(storeName);

        used.setMealContent(RLineUtils.getLineMeal(lineTime, account)); // 线租借套餐名称

        String password = getPwByNewLine(device.getId(), lineTime);
        used.setPassword(password);
        used.setIsActivity(checkDevIsActivity(device, date)); // 校验该设备是否满足要求
        used.setIsFree(appUser.getIsFree()); // VIP订单
        usedMapper.insertSelective(used);

        UsedBasics basics = new UsedBasics();
        basics.setUsedId(usedId);
        basics.setRentDate(date);
        basics.setBackDate(DateUtils.addMinutes(date, time)); // 记录归还时间
        basics.setIsBack(YesOrNoEnum.YES.getCode());
        basics.setRentDeviceId(device.getId());
        basics.setRentDeviceSn(device.getSn());
        basics.setBackDeviceId(device.getId());
        basics.setBackDeviceSn(device.getSn());
        usedBasicsMapper.insertUsedBasics(basics);


        JSONObject object = new JSONObject();
        object.put("used_id", used.getId());
        object.put("sn", device.getSn());
        object.put("password", password);
        return object;
    }

    /**
     * 查询用户正在租借中的订单个数
     *
     * @param appUserId
     * @return
     */
    @Override
    public int selectOnLoanCountByUid(String appUserId) {
        Example example = new Example(Used.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("leaseState", LeaseStateEnum.SUCCESS.getCode());
        criteria.andEqualTo("isBack", YesOrNoEnum.NO.getCode());
        criteria.andEqualTo("appUserId", appUserId);
        example.orderBy("createTime").desc();
        return usedMapper.selectCountByExample(example);
    }

    /**
     * 收益统计中 ---- 订单量统计
     *
     * @param map
     * @return
     */
    @Override
    public Long selectCountByMap(Map<String, String> map) {
        return usedMapper.selectCountByMap(map);
    }

    /**
     * 查询该门店的租借订单信息，已归还，且租借成功
     *
     * @param map
     * @return
     */
    @Override
    public List<Used> selectUsedListByApp(Map<String, String> map) {
        return usedMapper.selectUsedListByApp(map);
    }


    /**
     * 展示租借详情记录
     *
     * @param id
     * @return
     */
    @Override
    public UsedDetailVo selectUsedDetails(String id) {
        UsedDetailVo usedDetailVo = new UsedDetailVo();
        Used used = usedMapper.selectByPrimaryKey(id);
        usedDetailVo.setOrderNumber(used.getOrderNumber());
        if (used.getBorrowMode() == 2) {
            // 免押租借
            AuthUsed authUsed = authUsedMapper.selectByPrimaryKey(used.getId());
            usedDetailVo.setAuthNumber(authUsed.getTicket());
        } else {
            usedDetailVo.setAuthNumber("");
        }
        usedDetailVo.setCanRefund(1);
        if (StringUtils.isBlank(used.getTrueOrderId()) || used.getBorrowMode() == 1) {
            usedDetailVo.setCanRefund(0);
        }

        usedDetailVo.setOrderMonery(used.getAmountPaid().add(used.getDiscountAmount()));
        usedDetailVo.setAmountPaid(used.getAmountPaid());
        usedDetailVo.setDiscountAmount(used.getDiscountAmount());
        usedDetailVo.setRefundAmount(used.getRefundAmount());
        usedDetailVo.setAppUserId(used.getAppUserId());
        usedDetailVo.setCreateTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, used.getCreateTime()));
        usedDetailVo.setOrderPayTime("");
        usedDetailVo.setOrderReturnTime("");
        UsedBasics basics = usedBasicsMapper.selectByPrimaryKey(used.getId());
        usedDetailVo.setBatteryUpdateTime("");
        usedDetailVo.setBatterySn(basics.getBatterySn());

        usedDetailVo.setReturnDevSn("");
        usedDetailVo.setReturnSlot("");
        usedDetailVo.setPartnerName("");
        usedDetailVo.setPartnerPhone("");
        usedDetailVo.setStoreName("");
        usedDetailVo.setStoreCode("");
        usedDetailVo.setStoreAddress("");
        usedDetailVo.setStoreDetailAddress("");

        usedDetailVo.setBackMerchantMerchantPhone("");
        usedDetailVo.setBackMerchantName("");
        usedDetailVo.setBorMerchantName("");
        usedDetailVo.setBorMerchantPhone("");

        usedDetailVo.setStatus(used.getStatus());
        if (used.getStatus() == 0) {
            usedDetailVo.setStatusMsg(UsedStatusEnum.TO_BE_PAID.getValue());
        } else if (used.getStatus() == 1) {
            usedDetailVo.setStatusMsg(UsedStatusEnum.PAID.getValue());
        } else if (used.getStatus() == 2) {
            usedDetailVo.setStatusMsg(UsedStatusEnum.PURCHASED.getValue());
        } else {
            usedDetailVo.setStatusMsg(UsedStatusEnum.REFUND_SUCCESS.getValue());
        }

        usedDetailVo.setIsBack(used.getIsBack());
        boolean flag = false;
        if (used.getIsBack() == 1) {
            // 归还成功，必然借出成功
            // 订单状态 0 待支付 1 已支付 2 已购买 3 已退款
            if (used.getStatus() == 1) {
                // 支付时间
                usedDetailVo.setOrderPayTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, used.getPaymentTime()));
            }
            usedDetailVo.setOrderReturnTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, basics.getBackDate()));
            usedDetailVo.setBatteryStatus("正常");
            usedDetailVo.setBatteryUpdateTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, basics.getBackDate()));

            usedDetailVo.setReturnDevSn(basics.getBackDeviceSn());
            if (basics.getBackSlotNo() != null) {
                usedDetailVo.setReturnSlot(String.valueOf(basics.getBackSlotNo()));
            }

            if (StringUtils.isBlank(basics.getBackDeviceSn()) || basics.getBackDeviceSn().equals(basics.getRentDeviceSn())) {
                flag = true;
            } else {
                Device backDev = deviceMapper.selectByPrimaryKey(basics.getBackDeviceId());
                if (backDev != null) {
                    Partner backPartner = partnerMapper.selectByPrimaryKey(backDev.getPartnerId());
                    if (backPartner != null) {
                        usedDetailVo.setPartnerName(backPartner.getFullName());
                        usedDetailVo.setPartnerPhone(backPartner.getPhone());
                    }
                    Store backStore = storeMapper.selectByPrimaryKey(backDev.getMerchantId());
                    if (backStore != null) {
                        usedDetailVo.setStoreName(backStore.getStoreName());
                        usedDetailVo.setStoreCode(backStore.getId());
                        usedDetailVo.setStoreAddress(backStore.getLocation());
                        usedDetailVo.setStoreDetailAddress(backStore.getDetailAddress());
                    }
                    Merchant backMerchant = merchantMapper.selectByPrimaryKey(backDev.getMerchantId());
                    if (backMerchant != null) {
                        usedDetailVo.setBackMerchantName(backMerchant.getFullName());
                        usedDetailVo.setBackMerchantMerchantPhone(backMerchant.getPhone());
                    }
                }
            }
        } else {
            // 未归还
            // 租借状态 1 成功 2 失败 0 初始
            if (used.getLeaseState() == 1) {
                // 租借成功，但未归还
                usedDetailVo.setBatteryStatus("借出");
                usedDetailVo.setBatteryUpdateTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, basics.getRentDate()));
            } else if (used.getLeaseState() == 2) {
                usedDetailVo.setBatteryStatus("借出失败");
            }
        }
        usedDetailVo.setBorrowStatus(used.getLeaseState()); // 租借状态
        usedDetailVo.setBorrowSlot("");
        usedDetailVo.setBoorowDevSn(basics.getRentDeviceSn());
        if (basics.getRentSlotNo() != null) {
            usedDetailVo.setBorrowSlot(String.valueOf(basics.getRentSlotNo()));
        }
        usedDetailVo.setBorPartnerName("");
        usedDetailVo.setBorPartnerPhone("");
        Partner borPartner = partnerMapper.selectByPrimaryKey(used.getPartnerId());
        if (borPartner != null) {
            if (flag) {
                usedDetailVo.setPartnerName(borPartner.getFullName());
                usedDetailVo.setPartnerPhone(borPartner.getPhone());
            }
            usedDetailVo.setBorPartnerName(borPartner.getFullName());
            usedDetailVo.setBorPartnerPhone(borPartner.getPhone());
        }
        usedDetailVo.setBorStoreName("");
        usedDetailVo.setBorStoreCode("");
        usedDetailVo.setBorStoreAddress("");
        usedDetailVo.setBorStoreDetailAddress("");
        Store borStore = storeMapper.selectByPrimaryKey(used.getStoreId());
        if (borStore != null) {
            if (flag) {
                usedDetailVo.setStoreName(borStore.getStoreName());
                usedDetailVo.setStoreCode(borStore.getId());
                usedDetailVo.setStoreAddress(borStore.getLocation());
                usedDetailVo.setStoreDetailAddress(borStore.getDetailAddress());
            }
            usedDetailVo.setBorStoreName(borStore.getStoreName());
            usedDetailVo.setBorStoreCode(borStore.getId());
            usedDetailVo.setBorStoreAddress(borStore.getLocation());
            usedDetailVo.setBorStoreDetailAddress(borStore.getDetailAddress());
        }

        Merchant borMerchant = merchantMapper.selectByPrimaryKey(used.getMerchantId());
        if (borMerchant != null) {
            usedDetailVo.setBorMerchantName(borMerchant.getFullName());
            usedDetailVo.setBorMerchantPhone(borMerchant.getPhone());
        }
        usedDetailVo.setId(used.getId());
        return usedDetailVo;
    }

    /**
     * 查询将近99元的租借订单 by one
     *
     * @return
     */
    @Override
    public Used selectOneInOnUsed() {
        return usedMapper.selectOneInOnUsed();
    }

    /**
     * 定时任务 结束99元订单
     *
     * @param used
     * @param costPrice
     * @param backDate
     * @param entity
     * @return
     */
    @Transactional
    @Override
    public BatteryJSONResult taskEndDepositUsed(Used used, BigDecimal costPrice, Date backDate, AliPayEntity entity) {

        UsedBasics basics = usedBasicsMapper.selectByPrimaryKey(used.getId());

        Used usedUpdate = new Used();
        usedUpdate.setIsBack(YesOrNoEnum.YES.getCode());
        usedUpdate.setId(used.getId());
        usedUpdate.setAmountPaid(costPrice);
        usedUpdate.setDiscountAmount(BigDecimal.ZERO);
        usedUpdate.setUsingTime(DateUtils.getDateSecond(backDate, basics.getRentDate()) + ""); // TODO 计算使用时间 以秒为单位
        usedMapper.updateByPrimaryKeySelective(usedUpdate);

        UsedBasics basicsUpdate = new UsedBasics();
        basicsUpdate.setUsedId(used.getId());
        basicsUpdate.setBackDate(backDate); // 记录归还时间
        basicsUpdate.setIsBack(YesOrNoEnum.YES.getCode());
        usedBasicsMapper.updateByPrimaryKeySelective(basicsUpdate);

        Integer borrow_mode = used.getBorrowMode();
        Integer channel = used.getChannel();
        if (borrow_mode == BorrowModeEnum.DEPOSIT.type.intValue()) {
            Order noUsedDeposit = orderMapper.selectByPrimaryKey(used.getFalseOrderId());
            if (noUsedDeposit != null) {
                Order orderUpdate = new Order();
                orderUpdate.setId(noUsedDeposit.getId());
                orderUpdate.setIsUsed(YesOrNoEnum.YES.getCode());
                orderUpdate.setUsedId(used.getId());
                orderMapper.updateByPrimaryKeySelective(orderUpdate);

                // 同时更新对应租借记录
                Used usedUpdateD = new Used();
                usedUpdateD.setId(used.getId());
                usedUpdateD.setStatus(UsedStatusEnum.PURCHASED.getCode());
                usedUpdateD.setPaymentTime(backDate);
                usedMapper.updateByPrimaryKeySelective(usedUpdate);

                try {
                    incomeService.shareMoney(used.getId(), noUsedDeposit.getId());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return BatteryJSONResult.ok();
            }
        }
        if (UserTypeEnum.WX.getCode().intValue() == channel.intValue()) {
            // 微信租借，判断是押金租借，还是免押租借
            return completeWxUsed(used.getId());
        } else {
            // 支付宝预授权，授权转支付
            return freezeToPay(used.getId(), entity);
        }
    }

    /**
     * 查询处于初始状态的微信租借订单(最旧)
     *
     * @return
     */
    @Override
    public Used selectOneWxLeaseStateInInitialUsed() {
        return usedMapper.selectOneWxLeaseStateInInitialUsed();
    }

    /**
     * 查询处于初始状态的支付宝租借订单(最旧)
     *
     * @return
     */
    @Override
    public Used selectOneAliLeaseStateInInitialUsed() {
        return usedMapper.selectOneAliLeaseStateInInitialUsed();
    }


    /**
     * 授权转支付
     *
     * @param used_id
     * @param entity
     * @return
     */
    private BatteryJSONResult freezeToPay(String used_id, AliPayEntity entity) {
        Used used = usedMapper.selectByPrimaryKey(used_id);

        // TODO 查询是否已经生成了对应的支付订单
        Example example = new Example(Order.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("appUserId", used.getAppUserId());
        criteria.andEqualTo("channel", used.getChannel());
        criteria.andEqualTo("payType", OrderPayTypeEnum.ZFB_FREE.getCode());
        criteria.andEqualTo("orderType", OrderTypeEnum.DEV_BORROW_COST.type);
        criteria.andEqualTo("usedId", used_id);
        if (orderMapper.selectCountByExample(example) > 0) {
            // 大于0，直接返回
            return BatteryJSONResult.ok();
        }

        BigDecimal amount = used.getAmountPaid();
        String order_id = sid.nextShort();
        String outOrderNo = GenerateSeqUtil.generateEndRadomCode() + GenerateSeqUtil.getRandomCode(6);
        // 首先创建对应的授权支付订单
        Order order = new Order();
        order.setId(order_id);
        order.setAppUserId(used.getAppUserId());
        order.setProjectId(used.getProjectId());
        order.setPartnerId(used.getPartnerId());
        order.setMerchantId(used.getMerchantId());
        order.setStoreId(used.getStoreId());
        order.setOutOrderNo(outOrderNo);
        order.setChannel(used.getChannel());
        order.setTotalFee(amount);
        order.setTradeState(OrderTradeStateEnum.UNPAID.getCode()); // 未支付

        UsedBasics basics = usedBasicsMapper.selectByPrimaryKey(used_id);
        order.setCreatedTime(DateUtils.getNowDate());
        order.setSn(basics.getRentDeviceSn());
        order.setPayType(OrderPayTypeEnum.ZFB_FREE.getCode()); // 支付宝预授权
        order.setOrderType(OrderTypeEnum.DEV_BORROW_COST.type);
        order.setUsedId(used_id);
        // 保存订单信息
        orderMapper.insertSelective(order);

        AuthUsed authUsed = authUsedMapper.selectByPrimaryKey(used_id);


        AppUser appUser = appUserMapper.selectByPrimaryKey(used.getAppUserId());

        // 新的商户交易流水号 outOrderNo
        // 解冻转支付标题，用于展示在支付宝账单中
        String subject = "免电" + "充电宝订单支付";
        BatteryJSONResult result = AliPayUtils.tradePay(entity, outOrderNo, authUsed.getAuthNo(), subject, amount, appUser.getAppUserCode(), Constants.ali_freeze_pay_url);
        if (result.getCode() == 0) {
            // TODO 扣款失败，注意要记录对应的支付宝交易号
            AlipayTradePayResponse response = (AlipayTradePayResponse) result.getData();
            String trade_no = response.getTradeNo();
            if (StringUtils.isNotBlank(trade_no)) {
                Order updateOrder = new Order();
                updateOrder.setId(order_id);
                updateOrder.setTransactionId(trade_no); // 支付宝交易号（支付失败的情况下，该订单号非常重要）
                orderMapper.updateByPrimaryKeySelective(updateOrder);
            }

            Used usedUpdate = new Used();
            usedUpdate.setId(used_id);
            usedUpdate.setTrueOrderId(order_id);
            usedMapper.updateByPrimaryKeySelective(usedUpdate);
            return BatteryJSONResult.errorMsg(result.getMsg());
        }

        // 授权订单完成
        AuthUsed authUsedUpdate = new AuthUsed();
        authUsedUpdate.setUsedId(used_id);
        authUsedUpdate.setState(UsedAuthStateEnum.DONE.type);
        authUsedMapper.updateByPrimaryKeySelective(authUsedUpdate);

        Used usedUpdate = new Used();
        usedUpdate.setId(used_id);
        usedUpdate.setTrueOrderId(order_id);
        usedMapper.updateByPrimaryKeySelective(usedUpdate);

        AlipayTradePayResponse response = (AlipayTradePayResponse) result.getData();
        String trade_no = response.getTradeNo();
        Order updateOrder = new Order();
        updateOrder.setId(order_id);
        updateOrder.setTransactionId(trade_no);
        orderMapper.updateByPrimaryKeySelective(updateOrder);
        return BatteryJSONResult.ok();
    }


    private BatteryJSONResult depositAliEndUsed(String used_id, AliPayEntity entity, Date backDate) {
        Used used = usedMapper.selectByPrimaryKey(used_id);
        Order noUsedDeposit = orderMapper.selectByPrimaryKey(used.getFalseOrderId());
        if (noUsedDeposit != null) {
            if (noUsedDeposit.getTotalFee().subtract(used.getAmountPaid()).compareTo(BigDecimal.ZERO) == 0) {
                // 押金金额 等于 租借费用
                Order orderUpdate = new Order();
                orderUpdate.setId(noUsedDeposit.getId());
                orderUpdate.setIsUsed(YesOrNoEnum.YES.getCode());
                orderUpdate.setUsedId(used_id);
                orderMapper.updateByPrimaryKeySelective(orderUpdate);

                // 同时更新对应租借记录
                Used usedUpdate = new Used();
                usedUpdate.setId(used_id);
                usedUpdate.setStatus(UsedStatusEnum.PURCHASED.getCode());
                usedUpdate.setPaymentTime(backDate);
                usedMapper.updateByPrimaryKeySelective(usedUpdate);

                // TODO TODO 开始99元分成操作
                try {
                    incomeService.shareMoney(used_id, noUsedDeposit.getId());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                // 租借费用小于99元
//                int autoRefundYj = Integer.parseInt(configService.selectConfigByKeyNoCache("sys.borrow.autoRefundYj"));
//                if (autoRefundYj == 1) {
                // 自动退押金
                BigDecimal amountPaid = used.getAmountPaid();
                BigDecimal refund_fee = noUsedDeposit.getTotalFee().subtract(amountPaid);

                AppUser appUser = appUserMapper.selectByPrimaryKey(used.getAppUserId());
                Example example = new Example(RefundOrder.class);
                Example.Criteria criteria = example.createCriteria();
                criteria.andEqualTo("orderId", noUsedDeposit.getId());
                criteria.andEqualTo("refundStatus", RefundStatusEnum.CHANGE.getCode()); // 退款异常
                RefundOrder errRefund = refundOrderMapper.selectOneByExample(example);
                String out_refund_no = ""; // 退款单号
                String refundOrderId = null;
                if (errRefund != null) {
                    // 存在退款异常的订单
                    // 存在错误的退款订单，那么采用错误的退款订单来进行操作
                    out_refund_no = errRefund.getOutRefundNo();
                    RefundOrder orderUpdate = new RefundOrder();
                    orderUpdate.setId(errRefund.getId());
                    orderUpdate.setRefundFee(refund_fee);
                    orderUpdate.setRefundStatus(RefundStatusEnum.REQUEST_REFUND.getCode()); // 发起退款
                    refundOrderMapper.updateByPrimaryKeySelective(orderUpdate);

                    refundOrderId = errRefund.getId();
                } else {
                    out_refund_no = GenerateSeqUtil.generateEndRadomCode() + GenerateSeqUtil.getRandomCode(6);

                    RefundOrder refundOrder = new RefundOrder();
                    refundOrder.setId(sid.nextShort());
                    refundOrder.setAppUserId(appUser.getId());
                    refundOrder.setOutRefundNo(out_refund_no);
                    refundOrder.setTotalFee(noUsedDeposit.getTotalFee());
                    refundOrder.setRefundFee(refund_fee);
                    refundOrder.setRefundDesc("自动退押金");
                    refundOrder.setRefundStatus(RefundStatusEnum.REQUEST_REFUND.getCode()); // 发起退款
                    refundOrder.setCreateTime(DateUtils.getNowDate());
                    refundOrder.setOrderId(noUsedDeposit.getId());
                    refundOrder.setOrderType(noUsedDeposit.getOrderType());
                    refundOrder.setChannel(noUsedDeposit.getChannel());
                    refundOrderMapper.insertSelective(refundOrder);

                    // 查询新建的退款数据
                    refundOrderId = refundOrder.getId();
                }
                // 发起退款操作
                JSONObject requestRefundObj = new JSONObject();
                requestRefundObj.put("out_trade_no", noUsedDeposit.getOutOrderNo());
                requestRefundObj.put("trade_no", noUsedDeposit.getTransactionId());
                requestRefundObj.put("out_request_no", out_refund_no);
                requestRefundObj.put("refund_amount", refund_fee);
                BatteryJSONResult result = null;
                boolean flag = false;
                try {
                    result = AliPayUtils.tradeRefund(entity, requestRefundObj);
                } catch (Exception e) {
                    e.printStackTrace();
                    flag = true;
                }
                if (result == null || flag) {
                    // 支付宝退款抛出异常
                    RefundOrder updateRefundOrder = new RefundOrder();
                    updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
                    updateRefundOrder.setId(refundOrderId);
                    updateRefundOrder.setRemark("发起退押出现异常");
                    refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);
                    return BatteryJSONResult.errorMsg("发起退押出现异常");
                }
                AlipayTradeRefundResponse response = (AlipayTradeRefundResponse) result.getData();
                if (response.isSuccess()) {
                    // 退款成功
                    RefundOrder updateOrder = new RefundOrder();
                    updateOrder.setId(refundOrderId);
                    updateOrder.setRefundStatus(RefundStatusEnum.SUCCESS.getCode());
                    updateOrder.setSuccessTime(DateUtils.getNowDate());
                    refundOrderMapper.updateByPrimaryKeySelective(updateOrder);

                    // 更新原先订单状态
                    Order updateFormer = new Order();
                    updateFormer.setId(noUsedDeposit.getId());
                    updateFormer.setTradeState(OrderTradeStateEnum.REFUND_SUCCESS.getCode()); // 直接更新状态为退款成功
                    updateFormer.setRefundId(out_refund_no); // 退款订单号
                    updateFormer.setRefundMoney(refund_fee); // 退款金额
                    orderMapper.updateByPrimaryKeySelective(updateFormer);

                    // TODO 更新租借记录为已支付，同时进行分润操作
                    Used usedUpdate = new Used();
                    usedUpdate.setId(used_id);
                    usedUpdate.setStatus(UsedStatusEnum.PAID.getCode()); // 设置为已支付
                    usedUpdate.setTrueOrderId(noUsedDeposit.getId()); // 真实支付ID 为 押金订单ID
                    usedMapper.updateByPrimaryKeySelective(usedUpdate);

                    try {
                        incomeService.shareMoney(used.getId(), noUsedDeposit.getId());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                RefundOrder updateRefundOrder = new RefundOrder();
                updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
                updateRefundOrder.setId(refundOrderId);
                updateRefundOrder.setRemark("发起退押出现异常");
                refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);
                return BatteryJSONResult.errorMsg("退押失败,支付宝返回【" + response.getSubMsg() + "】"); // 返回错误描述
//                }
//                else {
//                    // TODO 不自动退押金
//                    AppUser appUser = appUserMapper.selectByPrimaryKey(used.getAppUserId());
//                    AppUser appUserUpdate = new AppUser();
//                    appUserUpdate.setId(appUser.getId());
//                    appUserUpdate.setBalance(appUser.getBalance().subtract(used.getAmountPaid()));
//                    appUserUpdate.setUpdateTime(backDate);
//                    appUserMapper.updateByPrimaryKeySelective(appUserUpdate);
//                    return BatteryJSONResult.ok();
//                }
            }
        }
        return BatteryJSONResult.ok();
    }


    /**
     * 押金结束订单
     *
     * @param used_id
     * @return
     */
    private BatteryJSONResult depositWxEndUsed(String used_id, Date backDate) {
        Used used = usedMapper.selectByPrimaryKey(used_id);
        // 查询该用户未使用押金
//        Example example = new Example(Order.class);
//        Example.Criteria criteria = example.createCriteria();
//        criteria.andEqualTo("appUserId", used.getAppUserId());
//        criteria.andEqualTo("channel", used.getChannel());
//        criteria.andEqualTo("tradeState", OrderTradeStateEnum.PAY_SUCCESS.getCode());
//        criteria.andEqualTo("orderType", OrderTypeEnum.DEPOSIT.type);
//        criteria.andEqualTo("isUsed", YesOrNoEnum.NO.getCode());
//        Order noUsedDeposit = orderMapper.selectOneByExample(example);
        Order noUsedDeposit = orderMapper.selectByPrimaryKey(used.getFalseOrderId());
        if (noUsedDeposit != null) {
            if (noUsedDeposit.getTotalFee().subtract(used.getAmountPaid()).compareTo(BigDecimal.ZERO) == 0) {
                // 存在未使用押金，且扣款金额等于押金金额
                // 直接将押金设置为已使用
                Order orderUpdate = new Order();
                orderUpdate.setId(noUsedDeposit.getId());
                orderUpdate.setIsUsed(YesOrNoEnum.YES.getCode());
                orderUpdate.setUsedId(used_id);
                orderMapper.updateByPrimaryKeySelective(orderUpdate);

                // 同时更新对应租借记录
                Used usedUpdate = new Used();
                usedUpdate.setId(used_id);
                usedUpdate.setStatus(UsedStatusEnum.PURCHASED.getCode());
                usedUpdate.setPaymentTime(backDate);
                usedMapper.updateByPrimaryKeySelective(usedUpdate);
                // TODO TODO 开始99元分成操作
                try {
                    incomeService.shareMoney(used_id, noUsedDeposit.getId());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                // 租借费用小于99元
//                int autoRefundYj = Integer.parseInt(configService.selectConfigByKeyNoCache("sys.borrow.autoRefundYj"));
//                if (autoRefundYj == 1) {
                BigDecimal amountPaid = used.getAmountPaid();
                BigDecimal refund_fee = noUsedDeposit.getTotalFee().subtract(amountPaid);

                AppUser appUser = appUserMapper.selectByPrimaryKey(used.getAppUserId());
                // TODO TODO
                Example example = new Example(RefundOrder.class);
                Example.Criteria criteria = example.createCriteria();
                criteria.andEqualTo("orderId", noUsedDeposit.getId());
                criteria.andEqualTo("refundStatus", RefundStatusEnum.CHANGE.getCode()); // 退款异常
                RefundOrder errRefund = refundOrderMapper.selectOneByExample(example);
                String out_refund_no = ""; // 退款单号
                String refundOrderId = null;
                if (errRefund != null) {
                    // 存在退款异常的订单
                    // 存在错误的退款订单，那么采用错误的退款订单来进行操作
                    out_refund_no = errRefund.getOutRefundNo();
                    RefundOrder orderUpdate = new RefundOrder();
                    orderUpdate.setId(errRefund.getId());
                    orderUpdate.setRefundFee(refund_fee);
                    orderUpdate.setRefundStatus(RefundStatusEnum.REQUEST_REFUND.getCode()); // 发起退款
                    refundOrderMapper.updateByPrimaryKeySelective(orderUpdate);
                    refundOrderId = errRefund.getId();
                } else {
                    // 退款单号
                    out_refund_no = GenerateSeqUtil.generateEndRadomCode() + GenerateSeqUtil.getRandomCode(6);
                    RefundOrder refundOrder = new RefundOrder();
                    refundOrder.setId(sid.nextShort());
                    refundOrder.setAppUserId(appUser.getId());
                    refundOrder.setOutRefundNo(out_refund_no);
                    refundOrder.setTotalFee(noUsedDeposit.getTotalFee());
                    refundOrder.setRefundFee(refund_fee);
                    refundOrder.setRefundDesc("自动退押金");
                    refundOrder.setRefundStatus(RefundStatusEnum.REQUEST_REFUND.getCode()); // 发起退款
                    refundOrder.setCreateTime(DateUtils.getNowDate());
                    refundOrder.setOrderId(noUsedDeposit.getId());
                    refundOrder.setOrderType(noUsedDeposit.getOrderType());
                    refundOrder.setChannel(noUsedDeposit.getChannel());
                    refundOrderMapper.insertSelective(refundOrder);
                    // 查询新建的退款数据
                    refundOrderId = refundOrder.getId();
                }
                // 发起退款操作
                WxPayRefundRequest refundRequest = new WxPayRefundRequest();
                refundRequest.setTransactionId(noUsedDeposit.getTransactionId());
                refundRequest.setOutRefundNo(out_refund_no);
                refundRequest.setTotalFee(noUsedDeposit.getTotalFee().multiply(new BigDecimal(100)).intValue());
                refundRequest.setRefundFee(refund_fee.multiply(new BigDecimal(100)).intValue());
                refundRequest.setNotifyUrl(Constants.wx_refund_callback_url); // 退款通知接口
                WxPayRefundResult refundResult = null;
                boolean flag = false;
                try {
                    refundResult = wxService.refund(refundRequest);
                } catch (WxPayException e) {
                    // 发生错误
                    e.printStackTrace();
                    flag = true;
                }
                if (refundResult == null || flag) {
                    // 调起微信退款接口发生错误
                    RefundOrder updateRefundOrder = new RefundOrder();
                    updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
                    updateRefundOrder.setId(refundOrderId);
                    updateRefundOrder.setRemark("发起退押出现异常");
                    refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);
                    return BatteryJSONResult.errorMsg("发起退押出现异常");
                }
                String return_code = refundResult.getReturnCode();
                String result_code = refundResult.getResultCode();
                if ("SUCCESS".equals(return_code) && "SUCCESS".equals(result_code)) {
                    // 发起退款接口成功，更新退款订单号
                    String refund_id = refundResult.getRefundId(); // 微信退款单号
                    RefundOrder updateOrder = new RefundOrder();
                    updateOrder.setId(refundOrderId);
                    updateOrder.setRefundId(refund_id);
                    refundOrderMapper.updateRefundOrder(updateOrder);

                    // 更新原先订单状态
                    Order updateFormer = new Order();
                    updateFormer.setId(noUsedDeposit.getId());
                    updateFormer.setTradeState(OrderTradeStateEnum.TO_REFUND.getCode()); // 转入退款
                    updateFormer.setRefundId(out_refund_no); // 退款订单号
                    updateFormer.setRefundMoney(refund_fee); // 退款金额
                    updateFormer.setUsedId(used_id); // 记录租借ID
                    orderMapper.updateByPrimaryKeySelective(updateFormer);
                    return BatteryJSONResult.ok();
                }
                // 调起微信退款接口发生错误
                RefundOrder updateRefundOrder = new RefundOrder();
                updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
                updateRefundOrder.setId(refundOrderId);
                updateRefundOrder.setRemark("发起退押出现异常");
                refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);
                return BatteryJSONResult.errorMsg("退押失败,微信返回【" + refundResult.getErrCodeDes() + "】"); // 返回错误描述
//                }
//                else {
//                    AppUser appUser = appUserMapper.selectByPrimaryKey(used.getAppUserId());
//                    AppUser appUserUpdate = new AppUser();
//                    appUserUpdate.setId(appUser.getId());
//                    appUserUpdate.setBalance(appUser.getBalance().subtract(used.getAmountPaid()));
//                    appUserUpdate.setUpdateTime(backDate);
//                    appUserMapper.updateByPrimaryKeySelective(appUserUpdate);
//                }
            }
            return BatteryJSONResult.ok();
        }
        return BatteryJSONResult.ok();
    }


    /**
     * 预授权租借0元结束订单，解冻处理
     *
     * @param used_id
     * @return
     */
    private BatteryJSONResult unfreezeToZero(String used_id, AliPayEntity entity) {

        AuthUsed authUsed = authUsedMapper.selectByPrimaryKey(used_id);
        String auth_no = authUsed.getAuthNo();
        String out_request_no = authUsed.getTicket();
        BigDecimal amount = authUsed.getAmount();
        BatteryJSONResult reponseResult = AliPayUtils.unfreeze(entity, auth_no, out_request_no, amount);
        boolean isSuc = false;
        if (reponseResult.getCode() == 0) {
            JSONObject responseJSON = (JSONObject) reponseResult.getData();
            String subCode = responseJSON.getString("sub_code");
            if ("ORDER_ALREADY_FINISH".equals(subCode) || "ORDER_ALREADY_CLOSED".equals(subCode)) {
                isSuc = true;
            }
        } else {
            isSuc = true;
        }
        if (isSuc || reponseResult.getCode() == 1) {
            // 解冻成功，更新状态
            AuthUsed authUsedUpdate = new AuthUsed();
            authUsedUpdate.setUsedId(used_id);
            authUsedUpdate.setState(UsedAuthStateEnum.PAID.type); // 订单已支付
            authUsedUpdate.setStateDescription(UsedAuthStateDescriptionEnum.USER_PAID.type); // 订单已支付
            authUsedMapper.updateByPrimaryKeySelective(authUsedUpdate);
            return BatteryJSONResult.ok();
        }
        return BatteryJSONResult.errorMsg("解冻授权订单出现错误");
    }


    /**
     * 微信支付分结束订单
     *
     * @param used_id
     * @return
     */
    private BatteryJSONResult completeWxUsed(String used_id) {

        Used used = usedMapper.selectByPrimaryKey(used_id);

        BigDecimal amount = used.getAmountPaid();

        JSONObject obj = new JSONObject();
        obj.put("appid", Constants.wxMinAppID);
        obj.put("service_id", Constants.wxServiceId);
        // 开电共享充电宝,租赁费用
        String serviceIntroduction = "免电共享充电宝" + "," + "租赁费用";
        JSONArray array = new JSONArray();
        JSONObject postPaymentsObj = new JSONObject();
        postPaymentsObj.put("name", serviceIntroduction);
        postPaymentsObj.put("amount", amount.multiply(new BigDecimal(100))); // 金额
        array.add(postPaymentsObj);
        obj.put("post_payments", array);
        obj.put("total_amount", amount.multiply(new BigDecimal(100)));
        JSONObject timeRangeObj = new JSONObject();
        timeRangeObj.put("end_time", DateUtils.parseDateToStr(DateUtils.YYYYMMDDHHMMSS, DateUtils.getNowDate()));
        obj.put("time_range", timeRangeObj);
        JSONObject locationObj = new JSONObject();
        locationObj.put("end_location", used.getStoreName());
        obj.put("Location", locationObj);
        BatteryJSONResult response = null;
        AuthUsed authUsed = authUsedMapper.selectByPrimaryKey(used_id);
        try {
            response = PayscoreUtils.complete(obj, authUsed.getOutOrderNo(), Constants.wxMerchantId, Constants.certSerialNo, Constants.wx_cret_keyPath_apiclient_key);
        } catch (Exception e) {
            e.printStackTrace();
            return BatteryJSONResult.errorMsg("完结微信支付分订单失败");
        }
        if (response == null) {
            return BatteryJSONResult.errorMsg("完结微信支付分订单失败");
        }
        if (response.getCode() == 0) {
            return response;
        }
        String body = (String) response.getData();
        JSONObject obj_ = JSONObject.parseObject(body);
        if (StringUtils.isNotBlank(obj_.getString("code"))) {
            return BatteryJSONResult.errorMsg("完结微信支付分订单失败");
        }
        String state = obj_.getString("state");
        if ("DOING".equals(state) || "DONE".equals(state)) {
            AuthUsed updateAuthUsed = new AuthUsed();
            updateAuthUsed.setUsedId(used_id);
            updateAuthUsed.setState(state);
            authUsedMapper.updateByPrimaryKeySelective(updateAuthUsed);
        }
        return BatteryJSONResult.ok();
    }

}
